@meetquinn/animactl 0.1.2 → 0.1.3
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/README.md +11 -6
- package/dist/server/{runtime/activity-payload.d.ts → activities/format.d.ts} +4 -1
- package/dist/server/activities/format.d.ts.map +1 -0
- package/dist/server/{runtime/activity-payload.js → activities/format.js} +16 -1
- package/dist/server/agents/agent-skills.d.ts +7 -3
- package/dist/server/agents/agent-skills.d.ts.map +1 -1
- package/dist/server/agents/agent-skills.js +243 -38
- package/dist/server/agents/agent-slack.service.d.ts +15 -0
- package/dist/server/agents/agent-slack.service.d.ts.map +1 -1
- package/dist/server/agents/agent-slack.service.js +43 -6
- package/dist/server/agents/default-skills.d.ts +9 -0
- package/dist/server/agents/default-skills.d.ts.map +1 -0
- package/dist/server/agents/default-skills.js +52 -0
- package/dist/server/cli/runtime-cli.d.ts +7 -1
- package/dist/server/cli/runtime-cli.d.ts.map +1 -1
- package/dist/server/cli/runtime-cli.js +107 -3
- package/dist/server/cli/services-cli.d.ts.map +1 -1
- package/dist/server/cli/services-cli.js +39 -0
- package/dist/server/inbox/slack-subscriber.d.ts +2 -0
- package/dist/server/inbox/slack-subscriber.d.ts.map +1 -1
- package/dist/server/inbox/slack-subscriber.js +28 -2
- package/dist/server/inbox/slack-subscription.service.d.ts.map +1 -1
- package/dist/server/inbox/slack-subscription.service.js +13 -1
- package/dist/server/inbox/wake-queue.service.d.ts +3 -1
- package/dist/server/inbox/wake-queue.service.d.ts.map +1 -1
- package/dist/server/inbox/wake-queue.service.js +5 -3
- package/dist/server/provider-usage/http.d.ts +1 -0
- package/dist/server/provider-usage/http.d.ts.map +1 -1
- package/dist/server/provider-usage/http.js +23 -1
- package/dist/server/provider-usage/provider-usage.service.d.ts +1 -4
- package/dist/server/provider-usage/provider-usage.service.d.ts.map +1 -1
- package/dist/server/provider-usage/provider-usage.service.js +1 -18
- package/dist/server/provider-usage/providers/claude.d.ts +1 -1
- package/dist/server/provider-usage/providers/claude.d.ts.map +1 -1
- package/dist/server/provider-usage/providers/claude.js +1 -1
- package/dist/server/provider-usage/providers/codex.d.ts +1 -1
- package/dist/server/provider-usage/providers/codex.d.ts.map +1 -1
- package/dist/server/provider-usage/providers/codex.js +1 -1
- package/dist/server/provider-usage/providers/kimi.d.ts +1 -1
- package/dist/server/provider-usage/providers/kimi.d.ts.map +1 -1
- package/dist/server/provider-usage/providers/kimi.js +4 -4
- package/dist/server/provider-usage/result.d.ts +5 -0
- package/dist/server/provider-usage/result.d.ts.map +1 -0
- package/dist/server/provider-usage/result.js +18 -0
- package/dist/server/providers/active-runtime.d.ts +1 -1
- package/dist/server/providers/active-runtime.d.ts.map +1 -1
- package/dist/server/providers/claude-events.d.ts +1 -1
- package/dist/server/providers/claude-events.d.ts.map +1 -1
- package/dist/server/providers/claude-events.js +2 -2
- package/dist/server/providers/claude.d.ts +1 -1
- package/dist/server/providers/claude.d.ts.map +1 -1
- package/dist/server/providers/claude.js +2 -2
- package/dist/server/providers/codex-app-server.d.ts +1 -1
- package/dist/server/providers/codex-app-server.d.ts.map +1 -1
- package/dist/server/providers/codex-app-server.js +1 -1
- package/dist/server/providers/codex-events.js +1 -1
- package/dist/server/providers/codex.d.ts +1 -1
- package/dist/server/providers/codex.d.ts.map +1 -1
- package/dist/server/providers/codex.js +2 -2
- package/dist/server/{runtime/provider-contract.d.ts → providers/contract.d.ts} +1 -1
- package/dist/server/providers/contract.d.ts.map +1 -0
- package/dist/server/providers/factory.d.ts +1 -1
- package/dist/server/providers/factory.d.ts.map +1 -1
- package/dist/server/providers/kimi-events.d.ts +1 -1
- package/dist/server/providers/kimi-events.d.ts.map +1 -1
- package/dist/server/providers/kimi-events.js +1 -1
- package/dist/server/providers/kimi.d.ts +1 -1
- package/dist/server/providers/kimi.d.ts.map +1 -1
- package/dist/server/providers/kimi.js +3 -2
- package/dist/server/providers/reasoning-events.js +1 -1
- package/dist/server/runtime/active-run-control.d.ts +19 -0
- package/dist/server/runtime/active-run-control.d.ts.map +1 -0
- package/dist/server/runtime/active-run-control.js +89 -0
- package/dist/server/runtime/activity.js +1 -1
- package/dist/server/runtime/agent-runner.d.ts +1 -1
- package/dist/server/runtime/agent-runner.d.ts.map +1 -1
- package/dist/server/runtime/delivery-prompt.d.ts +6 -0
- package/dist/server/runtime/delivery-prompt.d.ts.map +1 -1
- package/dist/server/runtime/delivery-prompt.js +53 -34
- package/dist/server/runtime/followup-appender.d.ts +20 -0
- package/dist/server/runtime/followup-appender.d.ts.map +1 -0
- package/dist/server/runtime/followup-appender.js +128 -0
- package/dist/server/runtime/host.d.ts +2 -0
- package/dist/server/runtime/host.d.ts.map +1 -1
- package/dist/server/runtime/host.js +8 -0
- package/dist/server/runtime/provider-runner.d.ts +16 -0
- package/dist/server/runtime/provider-runner.d.ts.map +1 -0
- package/dist/server/runtime/provider-runner.js +86 -0
- package/dist/server/runtime/runtime-bridge.d.ts +1 -1
- package/dist/server/runtime/runtime-bridge.d.ts.map +1 -1
- package/dist/server/runtime/runtime-session.service.d.ts +1 -1
- package/dist/server/runtime/runtime-session.service.d.ts.map +1 -1
- package/dist/server/runtime/runtime-session.service.js +1 -1
- package/dist/server/runtime/runtime-worker.d.ts +2 -10
- package/dist/server/runtime/runtime-worker.d.ts.map +1 -1
- package/dist/server/runtime/runtime-worker.js +60 -286
- package/dist/server/runtime-management/managed-runtime.d.ts.map +1 -0
- package/dist/server/runtime-management/runtime-release.d.ts.map +1 -0
- package/dist/server/{runtime → runtime-management}/runtime-upgrade.d.ts +1 -0
- package/dist/server/runtime-management/runtime-upgrade.d.ts.map +1 -0
- package/dist/server/{runtime → runtime-management}/runtime-upgrade.js +14 -0
- package/dist/server/services/system.service.d.ts +41 -0
- package/dist/server/services/system.service.d.ts.map +1 -0
- package/dist/server/services/system.service.js +154 -0
- package/dist/server/settings/settings.service.d.ts +2 -1
- package/dist/server/settings/settings.service.d.ts.map +1 -1
- package/dist/server/settings/settings.service.js +9 -1
- package/dist/server/slack/shortcuts.d.ts +0 -3
- package/dist/server/slack/shortcuts.d.ts.map +1 -1
- package/dist/server/slack/shortcuts.js +0 -3
- package/dist/server/slack-interactions/shortcut-ids.d.ts +4 -0
- package/dist/server/slack-interactions/shortcut-ids.d.ts.map +1 -0
- package/dist/server/slack-interactions/shortcut-ids.js +3 -0
- package/dist/server/slack-interactions/shortcut-views.d.ts +65 -0
- package/dist/server/slack-interactions/shortcut-views.d.ts.map +1 -0
- package/dist/server/slack-interactions/shortcut-views.js +211 -0
- package/dist/server/{slack → slack-interactions}/shortcut.service.d.ts +2 -47
- package/dist/server/slack-interactions/shortcut.service.d.ts.map +1 -0
- package/dist/server/slack-interactions/shortcut.service.js +227 -0
- package/dist/server/storage/jsonl-log.d.ts +9 -0
- package/dist/server/storage/jsonl-log.d.ts.map +1 -1
- package/dist/server/storage/jsonl-log.js +36 -1
- package/dist/server/storage/schema/server.store.d.ts +5 -0
- package/dist/server/storage/schema/server.store.d.ts.map +1 -1
- package/dist/server/storage/schema/server.store.js +2 -1
- package/dist/server/storage/schema/wake-queue.store.d.ts +15 -1
- package/dist/server/storage/schema/wake-queue.store.d.ts.map +1 -1
- package/dist/server/storage/schema/wake-queue.store.js +5 -3
- package/dist/server/tests/agent-config.test.d.ts +2 -0
- package/dist/server/tests/agent-config.test.d.ts.map +1 -0
- package/dist/server/tests/agent-config.test.js +229 -0
- package/dist/server/tests/agent-runtime.test.d.ts +2 -0
- package/dist/server/tests/agent-runtime.test.d.ts.map +1 -0
- package/dist/server/tests/agent-runtime.test.js +1110 -0
- package/dist/server/tests/agent-seed-memory.test.d.ts +2 -0
- package/dist/server/tests/agent-seed-memory.test.d.ts.map +1 -0
- package/dist/server/tests/agent-seed-memory.test.js +16 -0
- package/dist/server/tests/agent-skills.test.d.ts +2 -0
- package/dist/server/tests/agent-skills.test.d.ts.map +1 -0
- package/dist/server/tests/agent-skills.test.js +140 -0
- package/dist/server/tests/anima-home.d.ts +2 -0
- package/dist/server/tests/anima-home.d.ts.map +1 -0
- package/dist/server/tests/anima-home.js +4 -0
- package/dist/server/tests/cli-file.test.d.ts +2 -0
- package/dist/server/tests/cli-file.test.d.ts.map +1 -0
- package/dist/server/tests/cli-file.test.js +596 -0
- package/dist/server/tests/cli-message.test.d.ts +2 -0
- package/dist/server/tests/cli-message.test.d.ts.map +1 -0
- package/dist/server/tests/cli-message.test.js +1196 -0
- package/dist/server/tests/client-error-routes.test.d.ts +2 -0
- package/dist/server/tests/client-error-routes.test.d.ts.map +1 -0
- package/dist/server/tests/client-error-routes.test.js +163 -0
- package/dist/server/tests/config.test.d.ts +2 -0
- package/dist/server/tests/config.test.d.ts.map +1 -0
- package/dist/server/tests/config.test.js +497 -0
- package/dist/server/tests/default-skills.test.d.ts +2 -0
- package/dist/server/tests/default-skills.test.d.ts.map +1 -0
- package/dist/server/tests/default-skills.test.js +57 -0
- package/dist/server/tests/helpers/inbox.d.ts +10 -0
- package/dist/server/tests/helpers/inbox.d.ts.map +1 -0
- package/dist/server/tests/helpers/inbox.js +21 -0
- package/dist/server/tests/helpers/slack.d.ts +11 -0
- package/dist/server/tests/helpers/slack.d.ts.map +1 -0
- package/dist/server/tests/helpers/slack.js +17 -0
- package/dist/server/tests/helpers/state.d.ts +19 -0
- package/dist/server/tests/helpers/state.d.ts.map +1 -0
- package/dist/server/tests/helpers/state.js +69 -0
- package/dist/server/tests/inbox-slack-events.test.d.ts +2 -0
- package/dist/server/tests/inbox-slack-events.test.d.ts.map +1 -0
- package/dist/server/tests/inbox-slack-events.test.js +271 -0
- package/dist/server/tests/inbox.test.d.ts +2 -0
- package/dist/server/tests/inbox.test.d.ts.map +1 -0
- package/dist/server/tests/inbox.test.js +144 -0
- package/dist/server/tests/interactive-ask.test.d.ts +2 -0
- package/dist/server/tests/interactive-ask.test.d.ts.map +1 -0
- package/dist/server/tests/interactive-ask.test.js +387 -0
- package/dist/server/tests/kb.test.d.ts +2 -0
- package/dist/server/tests/kb.test.d.ts.map +1 -0
- package/dist/server/tests/kb.test.js +371 -0
- package/dist/server/tests/message.service.test.d.ts +2 -0
- package/dist/server/tests/message.service.test.d.ts.map +1 -0
- package/dist/server/tests/message.service.test.js +151 -0
- package/dist/server/tests/messages.test.d.ts +2 -0
- package/dist/server/tests/messages.test.d.ts.map +1 -0
- package/dist/server/tests/messages.test.js +12 -0
- package/dist/server/tests/prompt-attachments.test.d.ts +2 -0
- package/dist/server/tests/prompt-attachments.test.d.ts.map +1 -0
- package/dist/server/tests/prompt-attachments.test.js +274 -0
- package/dist/server/tests/provider-usage.test.d.ts +2 -0
- package/dist/server/tests/provider-usage.test.d.ts.map +1 -0
- package/dist/server/tests/provider-usage.test.js +97 -0
- package/dist/server/tests/reminders.test.d.ts +2 -0
- package/dist/server/tests/reminders.test.d.ts.map +1 -0
- package/dist/server/tests/reminders.test.js +383 -0
- package/dist/server/tests/runtime-cli.test.d.ts +2 -0
- package/dist/server/tests/runtime-cli.test.d.ts.map +1 -0
- package/dist/server/tests/runtime-cli.test.js +21 -0
- package/dist/server/tests/runtime-upgrade.test.d.ts +2 -0
- package/dist/server/tests/runtime-upgrade.test.d.ts.map +1 -0
- package/dist/server/tests/runtime-upgrade.test.js +307 -0
- package/dist/server/tests/runtime-worker.test.d.ts +2 -0
- package/dist/server/tests/runtime-worker.test.d.ts.map +1 -0
- package/dist/server/tests/runtime-worker.test.js +1021 -0
- package/dist/server/tests/runtime.test.d.ts +2 -0
- package/dist/server/tests/runtime.test.d.ts.map +1 -0
- package/dist/server/tests/runtime.test.js +354 -0
- package/dist/server/tests/services.test.d.ts +2 -0
- package/dist/server/tests/services.test.d.ts.map +1 -0
- package/dist/server/tests/services.test.js +636 -0
- package/dist/server/tests/slack-files.test.d.ts +2 -0
- package/dist/server/tests/slack-files.test.d.ts.map +1 -0
- package/dist/server/tests/slack-files.test.js +118 -0
- package/dist/server/tests/slack-shortcuts.test.d.ts +2 -0
- package/dist/server/tests/slack-shortcuts.test.d.ts.map +1 -0
- package/dist/server/tests/slack-shortcuts.test.js +310 -0
- package/dist/server/tests/slack.test.d.ts +2 -0
- package/dist/server/tests/slack.test.d.ts.map +1 -0
- package/dist/server/tests/slack.test.js +213 -0
- package/dist/server/tests/state-cache.test.d.ts +2 -0
- package/dist/server/tests/state-cache.test.d.ts.map +1 -0
- package/dist/server/tests/state-cache.test.js +184 -0
- package/dist/server/tests/subscriptions.test.d.ts +2 -0
- package/dist/server/tests/subscriptions.test.d.ts.map +1 -0
- package/dist/server/tests/subscriptions.test.js +292 -0
- package/dist/server/tests/system-service.test.d.ts +2 -0
- package/dist/server/tests/system-service.test.d.ts.map +1 -0
- package/dist/server/tests/system-service.test.js +20 -0
- package/dist/server/tests/url-routes.test.d.ts +2 -0
- package/dist/server/tests/url-routes.test.d.ts.map +1 -0
- package/dist/server/tests/url-routes.test.js +217 -0
- package/dist/server/tests/web-api.test.d.ts +2 -0
- package/dist/server/tests/web-api.test.d.ts.map +1 -0
- package/dist/server/tests/web-api.test.js +1759 -0
- package/dist/server/web/app.d.ts.map +1 -1
- package/dist/server/web/app.js +2 -0
- package/dist/server/web/client-error-routes.d.ts +3 -0
- package/dist/server/web/client-error-routes.d.ts.map +1 -0
- package/dist/server/web/client-error-routes.js +101 -0
- package/dist/server/web/system-routes.d.ts.map +1 -1
- package/dist/server/web/system-routes.js +21 -131
- package/dist/shared/agent-config.d.ts +8 -18
- package/dist/shared/agent-config.d.ts.map +1 -1
- package/dist/shared/agent-config.js +3 -4
- package/dist/shared/inbox.d.ts +27 -0
- package/dist/shared/inbox.d.ts.map +1 -1
- package/dist/shared/inbox.js +1 -0
- package/dist/shared/server-info.d.ts +6 -5
- package/dist/shared/server-info.d.ts.map +1 -1
- package/dist/shared/server-info.js +3 -1
- package/dist/shared/server-settings.d.ts +6 -0
- package/dist/shared/server-settings.d.ts.map +1 -1
- package/dist/shared/server-settings.js +1 -0
- package/dist/shared/skills.d.ts +24 -3
- package/dist/shared/skills.d.ts.map +1 -1
- package/dist/web/assets/activity-DHjip8tY.js +7 -0
- package/dist/web/assets/clipboard-D2NSC52v.js +1 -0
- package/dist/web/assets/{external-link-Dt0qTpmV.js → external-link-Bhr1WdRS.js} +1 -1
- package/dist/web/assets/{file-text-Dd9ys6py.js → file-text-CYMA_SMA.js} +1 -1
- package/dist/web/assets/{index-CzAQnbuO.js → index-CVpew409.js} +5 -5
- package/dist/web/assets/index-mh0uJTkY.css +2 -0
- package/dist/web/assets/kb-DDVpYkT9.js +35 -0
- package/dist/web/assets/profile-CBy6GNzp.js +1 -0
- package/dist/web/assets/reminders-Bbwb9QNT.js +1 -0
- package/dist/web/favicon.svg +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/templates/runtime-standing-prompt.md +16 -2
- package/templates/skills/find-skills/SKILL.md +133 -0
- package/dist/server/runtime/activity-payload.d.ts.map +0 -1
- package/dist/server/runtime/activity-text.d.ts +0 -4
- package/dist/server/runtime/activity-text.d.ts.map +0 -1
- package/dist/server/runtime/activity-text.js +0 -16
- package/dist/server/runtime/managed-runtime.d.ts.map +0 -1
- package/dist/server/runtime/provider-contract.d.ts.map +0 -1
- package/dist/server/runtime/runtime-release.d.ts.map +0 -1
- package/dist/server/runtime/runtime-upgrade.d.ts.map +0 -1
- package/dist/server/slack/shortcut.service.d.ts.map +0 -1
- package/dist/server/slack/shortcut.service.js +0 -493
- package/dist/web/assets/activity-BP0C81IV.js +0 -7
- package/dist/web/assets/globe-DmDZSgDP.js +0 -1
- package/dist/web/assets/index-DKecrvN0.css +0 -2
- package/dist/web/assets/kb-3wFeP2Jt.js +0 -32
- package/dist/web/assets/profile-D7wPZXW_.js +0 -1
- package/dist/web/assets/reminders-DOhroVwo.js +0 -1
- /package/dist/server/{runtime/provider-contract.js → providers/contract.js} +0 -0
- /package/dist/server/{runtime → runtime-management}/managed-runtime.d.ts +0 -0
- /package/dist/server/{runtime → runtime-management}/managed-runtime.js +0 -0
- /package/dist/server/{runtime → runtime-management}/runtime-release.d.ts +0 -0
- /package/dist/server/{runtime → runtime-management}/runtime-release.js +0 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { makeReminderInboxItem } from './helpers/inbox.js';
|
|
4
|
+
import { buildProviderCrashRetryDeliveryPrompt, buildRuntimeRestartContinuationDeliveryPrompt, buildCodeAgentDeliveryPrompt, } from '../runtime/delivery-prompt.js';
|
|
5
|
+
import { runtimeEnv } from '../runtime/runtime-bridge.js';
|
|
6
|
+
import { buildAnimaRuntimeProfile } from '../runtime/standing-prompt.js';
|
|
7
|
+
import { makeSlackEvent } from './helpers/slack.js';
|
|
8
|
+
function buildInput(opts) {
|
|
9
|
+
const event = makeSlackEvent({
|
|
10
|
+
channelId: opts.channelId ?? 'D-user',
|
|
11
|
+
...(opts.channelName ? { channelName: opts.channelName } : {}),
|
|
12
|
+
teamId: 'T-demo',
|
|
13
|
+
text: 'check this out',
|
|
14
|
+
...(opts.threadTs ? { threadTs: opts.threadTs } : {}),
|
|
15
|
+
ts: '1770000010.000001',
|
|
16
|
+
userId: 'U1',
|
|
17
|
+
...(opts.files ? { files: opts.files } : {}),
|
|
18
|
+
});
|
|
19
|
+
return { event, context: buildContext(event) };
|
|
20
|
+
}
|
|
21
|
+
function buildContext(event) {
|
|
22
|
+
const item = {
|
|
23
|
+
...event,
|
|
24
|
+
handling: {
|
|
25
|
+
createdAt: '2026-01-01T00:00:00.000Z',
|
|
26
|
+
status: 'queued',
|
|
27
|
+
updatedAt: '2026-01-01T00:00:00.000Z',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const session = {
|
|
31
|
+
createdAt: '2026-01-01T00:00:00.000Z',
|
|
32
|
+
updatedAt: '2026-01-01T00:00:00.000Z',
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
agentId: 'anima',
|
|
36
|
+
item,
|
|
37
|
+
session,
|
|
38
|
+
stateDir: '/tmp',
|
|
39
|
+
homePath: '/tmp/agents/anima',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
test('buildCodeAgentDeliveryPrompt includes the Slack message envelope for threads', () => {
|
|
43
|
+
const text = buildCodeAgentDeliveryPrompt(buildInput({
|
|
44
|
+
channelId: 'C-team',
|
|
45
|
+
channelName: 'team',
|
|
46
|
+
threadTs: '1770000020.000001',
|
|
47
|
+
}).event);
|
|
48
|
+
assert.match(text, /New Slack message:/);
|
|
49
|
+
assert.match(text, /\[channel=#team channel_id=C-team thread_ts=1770000020\.000001 message_ts=1770000010\.000001 time=[^ \]]+ user_id=U1\]/);
|
|
50
|
+
assert.doesNotMatch(text, /Reply command/);
|
|
51
|
+
});
|
|
52
|
+
test('buildCodeAgentDeliveryPrompt renders restart resumes as a short system continuation', () => {
|
|
53
|
+
const event = makeSlackEvent({
|
|
54
|
+
channelId: 'D-user',
|
|
55
|
+
eventId: 'evt-restart-resume-prompt',
|
|
56
|
+
handling: {
|
|
57
|
+
createdAt: '2026-01-01T00:00:00.000Z',
|
|
58
|
+
resumeReason: 'runtime_restart',
|
|
59
|
+
status: 'queued',
|
|
60
|
+
updatedAt: '2026-01-01T00:00:00.000Z',
|
|
61
|
+
},
|
|
62
|
+
teamId: 'T-demo',
|
|
63
|
+
text: 'do the expensive thing',
|
|
64
|
+
ts: '1770000010.000001',
|
|
65
|
+
userId: 'U1',
|
|
66
|
+
});
|
|
67
|
+
const text = buildCodeAgentDeliveryPrompt(event);
|
|
68
|
+
assert.equal(text, buildRuntimeRestartContinuationDeliveryPrompt());
|
|
69
|
+
assert.doesNotMatch(text, /New Slack message/);
|
|
70
|
+
assert.doesNotMatch(text, /do the expensive thing/);
|
|
71
|
+
});
|
|
72
|
+
test('delivery prompt module exposes named provider-facing Anima builders', () => {
|
|
73
|
+
assert.match(buildRuntimeRestartContinuationDeliveryPrompt(), /runtime restarted/);
|
|
74
|
+
assert.equal(buildProviderCrashRetryDeliveryPrompt({
|
|
75
|
+
attempt: 2,
|
|
76
|
+
maxRetries: 3,
|
|
77
|
+
previousError: 'boom',
|
|
78
|
+
}), [
|
|
79
|
+
'Anima system note: the previous provider process crashed before completing this same item.',
|
|
80
|
+
'This is retry 2/3.',
|
|
81
|
+
'Previous error: boom',
|
|
82
|
+
'Continue the original task from the current files, conversation, and Slack state.',
|
|
83
|
+
'Do not repeat completed external side effects such as Slack messages, file sends, or file edits; inspect state first if needed.',
|
|
84
|
+
].join('\n'));
|
|
85
|
+
});
|
|
86
|
+
test('buildCodeAgentDeliveryPrompt omits channel_id for DMs (channel= already shows the raw id) and still emits user_id', () => {
|
|
87
|
+
const text = buildCodeAgentDeliveryPrompt(buildInput({ channelId: 'D-user' }).event);
|
|
88
|
+
assert.match(text, /\[channel=D-user message_ts=1770000010\.000001 time=[^ \]]+ user_id=U1\]/);
|
|
89
|
+
assert.doesNotMatch(text, /channel_id=/);
|
|
90
|
+
});
|
|
91
|
+
test('buildCodeAgentDeliveryPrompt includes triggering user local time when timezone is known', () => {
|
|
92
|
+
const event = makeSlackEvent({
|
|
93
|
+
channelId: 'D-user',
|
|
94
|
+
teamId: 'T-demo',
|
|
95
|
+
text: 'good morning',
|
|
96
|
+
timestamp: '2026-05-19T23:59:30.000Z',
|
|
97
|
+
ts: '1779235170.792609',
|
|
98
|
+
userId: 'U1',
|
|
99
|
+
});
|
|
100
|
+
event.actor = {
|
|
101
|
+
...event.actor,
|
|
102
|
+
timezone: {
|
|
103
|
+
label: 'China Standard Time',
|
|
104
|
+
name: 'Asia/Shanghai',
|
|
105
|
+
offsetSeconds: 28800,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
const text = buildCodeAgentDeliveryPrompt(event);
|
|
109
|
+
assert.match(text, /user_local_time=2026-05-20T07:59:30\+08:00 user_tz=Asia\/Shanghai/);
|
|
110
|
+
});
|
|
111
|
+
test('buildCodeAgentDeliveryPrompt renders scheduled reminders as the current event', () => {
|
|
112
|
+
const event = makeReminderInboxItem({
|
|
113
|
+
reminderId: 'reminder-test',
|
|
114
|
+
timestamp: '2026-05-18T17:00:00.000Z',
|
|
115
|
+
});
|
|
116
|
+
const text = buildCodeAgentDeliveryPrompt(event, {
|
|
117
|
+
reminder: {
|
|
118
|
+
createdAt: '2026-05-18T16:00:00.000Z',
|
|
119
|
+
firedCount: 0,
|
|
120
|
+
instructions: 'Check whether the deploy finished.',
|
|
121
|
+
reminderId: 'reminder-test',
|
|
122
|
+
schedule: { kind: 'once' },
|
|
123
|
+
status: 'scheduled',
|
|
124
|
+
title: 'Follow up on deploy',
|
|
125
|
+
updatedAt: '2026-05-18T16:00:00.000Z',
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
assert.match(text, /^Scheduled reminder:\n\n\[reminder_id=reminder-test time=2026-05-18T17:00:00\.000Z\] Scheduled wake: Follow up on deploy/);
|
|
129
|
+
assert.match(text, /Instructions:\nCheck whether the deploy finished\./);
|
|
130
|
+
assert.doesNotMatch(text, /Reply command|Recovery context/);
|
|
131
|
+
});
|
|
132
|
+
test('buildCodeAgentDeliveryPrompt renders onboarding as an onboarding wake, not a Slack DM', () => {
|
|
133
|
+
const text = buildCodeAgentDeliveryPrompt({
|
|
134
|
+
channelId: 'D-owner',
|
|
135
|
+
handling: {
|
|
136
|
+
createdAt: '2026-01-01T00:00:00.000Z',
|
|
137
|
+
queuedAt: '2026-01-01T00:00:00.000Z',
|
|
138
|
+
status: 'queued',
|
|
139
|
+
updatedAt: '2026-01-01T00:00:00.000Z',
|
|
140
|
+
},
|
|
141
|
+
id: 'agent-onboarding:anima:U-owner',
|
|
142
|
+
kind: 'onboarding',
|
|
143
|
+
operator: {
|
|
144
|
+
displayName: 'Iris',
|
|
145
|
+
handle: 'iris',
|
|
146
|
+
slackUserId: 'U-owner',
|
|
147
|
+
},
|
|
148
|
+
receivedAt: '2026-01-01T00:00:00.000Z',
|
|
149
|
+
teamId: 'T-demo',
|
|
150
|
+
text: 'Iris (<@U-owner>) just set you up here.',
|
|
151
|
+
});
|
|
152
|
+
assert.match(text, /^Agent onboarding:/);
|
|
153
|
+
assert.match(text, /\[owner=Iris \(@iris, <@U-owner>\) channel=D-owner time=2026-01-01T00:00:00\.000Z\]/);
|
|
154
|
+
assert.match(text, /Use `anima message send --channel D-owner` to reply to Iris/);
|
|
155
|
+
assert.doesNotMatch(text, /^New Slack message:/);
|
|
156
|
+
});
|
|
157
|
+
test('buildCodeAgentDeliveryPrompt treats legacy Slack-shaped onboarding as onboarding', () => {
|
|
158
|
+
const event = makeSlackEvent({
|
|
159
|
+
channelId: 'D-owner',
|
|
160
|
+
eventId: 'agent-onboarding:anima:U-owner',
|
|
161
|
+
teamId: 'T-demo',
|
|
162
|
+
text: 'Iris (<@U-owner>) just set you up here.',
|
|
163
|
+
userId: 'U-owner',
|
|
164
|
+
});
|
|
165
|
+
const text = buildCodeAgentDeliveryPrompt(event);
|
|
166
|
+
assert.match(text, /^Agent onboarding:/);
|
|
167
|
+
assert.match(text, /\[owner=<@U-owner> channel=D-owner time=/);
|
|
168
|
+
assert.doesNotMatch(text, /^New Slack message:/);
|
|
169
|
+
});
|
|
170
|
+
test('buildCodeAgentDeliveryPrompt emits <attached_files> metadata and omits block when no files', () => {
|
|
171
|
+
const text = buildCodeAgentDeliveryPrompt(buildInput({
|
|
172
|
+
files: [
|
|
173
|
+
{
|
|
174
|
+
id: 'F-img',
|
|
175
|
+
mimetype: 'image/png',
|
|
176
|
+
name: 'screenshot.png',
|
|
177
|
+
sizeBytes: 4096,
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
}).event);
|
|
181
|
+
assert.match(text, /<attached_files>/);
|
|
182
|
+
assert.match(text, /name="screenshot\.png"/);
|
|
183
|
+
assert.match(text, /mimetype="image\/png"/);
|
|
184
|
+
assert.doesNotMatch(text, /path=/);
|
|
185
|
+
assert.match(text, /size_bytes="4096"/);
|
|
186
|
+
assert.doesNotMatch(buildCodeAgentDeliveryPrompt(buildInput({}).event), /<attached_files>/);
|
|
187
|
+
});
|
|
188
|
+
test('buildAnimaRuntimeProfile tells agents to use message envelopes for Slack targets', () => {
|
|
189
|
+
const text = buildAnimaRuntimeProfile({ displayName: 'Iris', role: 'Product PM for prioritization.' });
|
|
190
|
+
assert.doesNotMatch(text, /\{\{name\}\}|\{\{role\}\}/);
|
|
191
|
+
assert.match(text, /Reply target comes from the delivery envelope/);
|
|
192
|
+
assert.match(text, /pass its `channel=` \/ `thread_ts=` to `--channel` \/ `--thread-ts` literally/);
|
|
193
|
+
assert.match(text, /You always receive DMs and any message that @mentions you/);
|
|
194
|
+
assert.match(text, /Only `mute` a thread\/channel when it's clearly done with you AND still noisy/);
|
|
195
|
+
assert.match(text, /anima reminder/);
|
|
196
|
+
assert.match(text, /anima message send --channel <id-or-name> \[--thread-ts <thread_ts>\]/);
|
|
197
|
+
assert.doesNotMatch(text, /\$ANIMA_CHANNEL|\$ANIMA_THREAD/);
|
|
198
|
+
});
|
|
199
|
+
test('buildAnimaRuntimeProfile keeps MEMORY.md as a short recovery index', () => {
|
|
200
|
+
const text = buildAnimaRuntimeProfile({ displayName: 'Iris', role: 'Product PM for prioritization.' });
|
|
201
|
+
assert.match(text, /an index, not a corpus/);
|
|
202
|
+
assert.match(text, /roughly one screen/);
|
|
203
|
+
assert.match(text, /notes\/<topic>\.md/);
|
|
204
|
+
assert.match(text, /Keep `Active Context` current/);
|
|
205
|
+
assert.match(text, /section grows past a short paragraph/);
|
|
206
|
+
});
|
|
207
|
+
test('buildAnimaRuntimeProfile injects agent name and role into the opening identity line', () => {
|
|
208
|
+
const withRole = buildAnimaRuntimeProfile({ displayName: 'Iris', role: 'Product PM for prioritization.' });
|
|
209
|
+
assert.match(withRole, /You are Iris, Product PM for prioritization\./);
|
|
210
|
+
const noRole = buildAnimaRuntimeProfile({ displayName: 'Anima' });
|
|
211
|
+
assert.match(noRole, /You are Anima, general-purpose Anima agent\./);
|
|
212
|
+
});
|
|
213
|
+
test('runtimeEnv exposes the current inbox item identity', () => {
|
|
214
|
+
const { context } = buildInput({ channelId: 'C-team' });
|
|
215
|
+
const env = runtimeEnv(context, {
|
|
216
|
+
ANIMA_AGENT_ID: 'wrong-agent',
|
|
217
|
+
ANIMA_INBOX_ITEM_ID: 'wrong-item',
|
|
218
|
+
PATH: '/tmp/bin',
|
|
219
|
+
});
|
|
220
|
+
assert.equal(env.ANIMA_AGENT_ID, 'anima');
|
|
221
|
+
assert.equal(env.ANIMA_HOME, '/tmp');
|
|
222
|
+
assert.equal(env.ANIMA_INBOX_ITEM_ID, context.item.id);
|
|
223
|
+
assert.match(env.PATH ?? '', /^.*\/bin:\/tmp\/bin$/);
|
|
224
|
+
});
|
|
225
|
+
test('buildCodeAgentDeliveryPrompt renders text files as self-closing metadata references', () => {
|
|
226
|
+
const text = buildCodeAgentDeliveryPrompt(buildInput({
|
|
227
|
+
files: [
|
|
228
|
+
{
|
|
229
|
+
id: 'F-text',
|
|
230
|
+
mimetype: 'text/plain',
|
|
231
|
+
name: 'note.txt',
|
|
232
|
+
sizeBytes: 12,
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
}).event);
|
|
236
|
+
assert.match(text, /<file id="F-text"/);
|
|
237
|
+
assert.match(text, /name="note\.txt"/);
|
|
238
|
+
assert.doesNotMatch(text, /path=/);
|
|
239
|
+
assert.match(text, /\/>/);
|
|
240
|
+
// No inlined content; agent uses Read tool.
|
|
241
|
+
assert.doesNotMatch(text, /hello prompt|truncated|<\/file>/);
|
|
242
|
+
});
|
|
243
|
+
test('buildCodeAgentDeliveryPrompt omits path for files deferred to manual fetch', () => {
|
|
244
|
+
const text = buildCodeAgentDeliveryPrompt(buildInput({
|
|
245
|
+
files: [
|
|
246
|
+
{
|
|
247
|
+
id: 'F-big',
|
|
248
|
+
mimetype: 'application/octet-stream',
|
|
249
|
+
name: 'recording.mov',
|
|
250
|
+
sizeBytes: 50 * 1024 * 1024,
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
}).event);
|
|
254
|
+
assert.match(text, /id="F-big"/);
|
|
255
|
+
assert.match(text, /name="recording\.mov"/);
|
|
256
|
+
assert.doesNotMatch(text, /path=/);
|
|
257
|
+
assert.doesNotMatch(text, /error=/);
|
|
258
|
+
});
|
|
259
|
+
test('buildCodeAgentDeliveryPrompt renders download errors as a self-closing file tag', () => {
|
|
260
|
+
const text = buildCodeAgentDeliveryPrompt(buildInput({
|
|
261
|
+
files: [
|
|
262
|
+
{
|
|
263
|
+
id: 'F-failed',
|
|
264
|
+
mimetype: 'image/png',
|
|
265
|
+
name: 'broken.png',
|
|
266
|
+
sizeBytes: 0,
|
|
267
|
+
downloadError: 'HTTP 403 Forbidden',
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
}).event);
|
|
271
|
+
assert.match(text, /name="broken\.png"/);
|
|
272
|
+
assert.match(text, /error="HTTP 403 Forbidden"/);
|
|
273
|
+
assert.match(text, /\/>/);
|
|
274
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-usage.test.d.ts","sourceRoot":"","sources":["../../../server/tests/provider-usage.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { ProviderUsageService } from '../provider-usage/provider-usage.service.js';
|
|
4
|
+
import { providerUsageNetworkErrorMessage } from '../provider-usage/http.js';
|
|
5
|
+
import { parseClaudeUsageResponse } from '../provider-usage/providers/claude.js';
|
|
6
|
+
import { parseCodexUsageResponse } from '../provider-usage/providers/codex.js';
|
|
7
|
+
import { parseKimiUsageResponse } from '../provider-usage/providers/kimi.js';
|
|
8
|
+
test('Claude usage parser returns remaining windows and extra usage', () => {
|
|
9
|
+
const parsed = parseClaudeUsageResponse({
|
|
10
|
+
extra_usage: {
|
|
11
|
+
currency: 'usd',
|
|
12
|
+
is_enabled: true,
|
|
13
|
+
monthly_limit: 4000,
|
|
14
|
+
used_credits: 250,
|
|
15
|
+
},
|
|
16
|
+
five_hour: { resets_at: '2026-05-29T06:00:00.000Z', utilization: 7 },
|
|
17
|
+
seven_day: { resets_at: '2026-06-01T00:00:00.000Z', utilization: 4 },
|
|
18
|
+
seven_day_sonnet: { resets_at: '2026-06-01T00:00:00.000Z', utilization: 2 },
|
|
19
|
+
}, { subscriptionType: 'max' });
|
|
20
|
+
assert.equal(parsed.error, undefined);
|
|
21
|
+
assert.deepEqual(parsed.windows.map(({ label, remainingPercent }) => [label, remainingPercent]), [
|
|
22
|
+
['5h', 93],
|
|
23
|
+
['Weekly', 96],
|
|
24
|
+
['Weekly Sonnet', 98],
|
|
25
|
+
]);
|
|
26
|
+
assert.deepEqual(parsed.extras, [
|
|
27
|
+
{ balance: 'Claude Max', label: 'Plan' },
|
|
28
|
+
{ currency: 'USD', label: 'Extra Usage', limit: 40, used: 2.5 },
|
|
29
|
+
]);
|
|
30
|
+
});
|
|
31
|
+
test('Codex usage parser returns rate-limit windows and credits', () => {
|
|
32
|
+
const parsed = parseCodexUsageResponse({
|
|
33
|
+
credits: { balance: '0', has_credits: false, unlimited: false },
|
|
34
|
+
plan_type: 'pro',
|
|
35
|
+
rate_limit: {
|
|
36
|
+
primary_window: { limit_window_seconds: 18000, reset_after_seconds: 60, used_percent: 8 },
|
|
37
|
+
secondary_window: { limit_window_seconds: 604800, reset_after_seconds: 120, used_percent: 56 },
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
assert.equal(parsed.error, undefined);
|
|
41
|
+
assert.deepEqual(parsed.windows.map(({ label, remainingPercent, windowSeconds }) => [label, remainingPercent, windowSeconds]), [
|
|
42
|
+
['5h', 92, 18000],
|
|
43
|
+
['Weekly', 44, 604800],
|
|
44
|
+
]);
|
|
45
|
+
assert.deepEqual(parsed.extras, [
|
|
46
|
+
{ balance: 'pro', label: 'Plan' },
|
|
47
|
+
{ balance: '0', label: 'Credits', unlimited: false },
|
|
48
|
+
]);
|
|
49
|
+
});
|
|
50
|
+
test('Kimi usage parser returns top-level and short-window limits', () => {
|
|
51
|
+
const parsed = parseKimiUsageResponse({
|
|
52
|
+
limits: [
|
|
53
|
+
{
|
|
54
|
+
detail: { limit: '100', remaining: '99', resetTime: '2026-05-29T08:00:00.000Z', used: '1' },
|
|
55
|
+
window: { duration: 5, timeUnit: 'TIME_UNIT_HOUR' },
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
usage: { limit: 100, remaining: 99, resetTime: '2026-06-01T00:00:00.000Z', used: 1 },
|
|
59
|
+
});
|
|
60
|
+
assert.equal(parsed.error, undefined);
|
|
61
|
+
assert.deepEqual(parsed.windows.map(({ label, remainingPercent, usedPercent }) => [label, remainingPercent, usedPercent]), [
|
|
62
|
+
['5h', 99, 1],
|
|
63
|
+
['Weekly', 99, 1],
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
66
|
+
test('provider usage network errors are classified without raw fetch wording', () => {
|
|
67
|
+
const abortError = new Error('This operation was aborted');
|
|
68
|
+
abortError.name = 'AbortError';
|
|
69
|
+
const dnsError = new Error('fetch failed');
|
|
70
|
+
dnsError.cause = { code: 'ENOTFOUND' };
|
|
71
|
+
assert.equal(providerUsageNetworkErrorMessage(abortError), 'Provider usage request timed out.');
|
|
72
|
+
assert.equal(providerUsageNetworkErrorMessage(dnsError), 'Provider usage service could not be resolved.');
|
|
73
|
+
assert.equal(providerUsageNetworkErrorMessage(new Error('fetch failed')), 'Provider usage request could not reach the provider service.');
|
|
74
|
+
});
|
|
75
|
+
test('provider usage service isolates adapter failures per provider', async () => {
|
|
76
|
+
const service = new ProviderUsageService([
|
|
77
|
+
{
|
|
78
|
+
fetch: async () => ({ extras: [], status: 'available', windows: [{ label: '5h', remainingPercent: 92 }] }),
|
|
79
|
+
label: 'Good',
|
|
80
|
+
provider: 'codex-cli',
|
|
81
|
+
source: 'private-api',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
fetch: async () => {
|
|
85
|
+
throw new Error('private endpoint changed');
|
|
86
|
+
},
|
|
87
|
+
label: 'Bad',
|
|
88
|
+
provider: 'claude-code',
|
|
89
|
+
source: 'private-api',
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
const response = await service.list();
|
|
93
|
+
assert.equal(response.providers.length, 2);
|
|
94
|
+
assert.equal(response.providers[0]?.status, 'available');
|
|
95
|
+
assert.equal(response.providers[1]?.status, 'unavailable');
|
|
96
|
+
assert.equal(response.providers[1]?.error?.type, 'unknown');
|
|
97
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reminders.test.d.ts","sourceRoot":"","sources":["../../../server/tests/reminders.test.ts"],"names":[],"mappings":""}
|