bazilion 0.0.0 → 0.1.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/README.md +53 -152
- package/dist/cli.js +2730 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon.js +5888 -0
- package/dist/daemon.js.map +1 -0
- package/dist/worker.js +1830 -0
- package/dist/worker.js.map +1 -0
- package/package.json +57 -28
- package/.understand-anything/.understandignore +0 -25
- package/.understand-anything/fingerprints.json +0 -14267
- package/.understand-anything/knowledge-graph.json +0 -18128
- package/.understand-anything/meta.json +0 -6
- package/CLAUDE.md +0 -164
- package/apps/cli/package.json +0 -21
- package/apps/cli/src/auth-file.ts +0 -18
- package/apps/cli/src/client.ts +0 -37
- package/apps/cli/src/columnize.ts +0 -32
- package/apps/cli/src/commands/agent.ts +0 -574
- package/apps/cli/src/commands/auth.ts +0 -110
- package/apps/cli/src/commands/backup.ts +0 -135
- package/apps/cli/src/commands/completion.ts +0 -155
- package/apps/cli/src/commands/config.ts +0 -95
- package/apps/cli/src/commands/doctor.ts +0 -131
- package/apps/cli/src/commands/group.ts +0 -132
- package/apps/cli/src/commands/inbox.ts +0 -82
- package/apps/cli/src/commands/login.ts +0 -73
- package/apps/cli/src/commands/memory.ts +0 -106
- package/apps/cli/src/commands/profile.ts +0 -259
- package/apps/cli/src/commands/provider.ts +0 -170
- package/apps/cli/src/commands/send.ts +0 -24
- package/apps/cli/src/commands/serve.ts +0 -89
- package/apps/cli/src/commands/skill.ts +0 -120
- package/apps/cli/src/commands/token.ts +0 -148
- package/apps/cli/src/commands/trigger.ts +0 -129
- package/apps/cli/src/commands/uninstall.ts +0 -156
- package/apps/cli/src/index.ts +0 -196
- package/apps/cli/src/paths.ts +0 -12
- package/apps/cli/test/agent.test.ts +0 -213
- package/apps/cli/test/backup.test.ts +0 -95
- package/apps/cli/test/chat.test.ts +0 -539
- package/apps/cli/test/columnize.test.ts +0 -29
- package/apps/cli/test/completion.test.ts +0 -45
- package/apps/cli/test/config-page.test.ts +0 -151
- package/apps/cli/test/group.test.ts +0 -74
- package/apps/cli/test/helpers.ts +0 -70
- package/apps/cli/test/inbox-autodeliver.test.ts +0 -143
- package/apps/cli/test/inbox.test.ts +0 -147
- package/apps/cli/test/memory.test.ts +0 -69
- package/apps/cli/test/profile.test.ts +0 -110
- package/apps/cli/test/send.test.ts +0 -30
- package/apps/cli/test/server-fixture.ts +0 -212
- package/apps/cli/test/session-head.test.ts +0 -45
- package/apps/cli/test/skill.test.ts +0 -128
- package/apps/cli/test/token.test.ts +0 -109
- package/apps/cli/test/trigger.test.ts +0 -245
- package/apps/cli/tsconfig.json +0 -4
- package/apps/daemon/package.json +0 -31
- package/apps/daemon/src/app.ts +0 -41
- package/apps/daemon/src/core/agent/archive.ts +0 -8
- package/apps/daemon/src/core/agent/delete.ts +0 -30
- package/apps/daemon/src/core/agent/resolve.ts +0 -31
- package/apps/daemon/src/core/agent/spawn.ts +0 -95
- package/apps/daemon/src/core/agent/unarchive.ts +0 -11
- package/apps/daemon/src/core/availableModels.ts +0 -58
- package/apps/daemon/src/core/db/client.ts +0 -113
- package/apps/daemon/src/core/db/migrate.ts +0 -41
- package/apps/daemon/src/core/db/migrations/0001_init.sql +0 -179
- package/apps/daemon/src/core/group/delete.ts +0 -21
- package/apps/daemon/src/core/group/register.ts +0 -68
- package/apps/daemon/src/core/index.ts +0 -71
- package/apps/daemon/src/core/paths.ts +0 -56
- package/apps/daemon/src/core/profile/create.ts +0 -78
- package/apps/daemon/src/core/profile/delete.ts +0 -26
- package/apps/daemon/src/core/profile/identity.ts +0 -70
- package/apps/daemon/src/core/profile/load.ts +0 -45
- package/apps/daemon/src/core/profile/seed.ts +0 -74
- package/apps/daemon/src/core/profile/templates.ts +0 -60
- package/apps/daemon/src/core/profile/update.ts +0 -57
- package/apps/daemon/src/core/profile/validate.ts +0 -9
- package/apps/daemon/src/core/repos/agents.ts +0 -202
- package/apps/daemon/src/core/repos/config.ts +0 -78
- package/apps/daemon/src/core/repos/groups.ts +0 -55
- package/apps/daemon/src/core/repos/messages.ts +0 -127
- package/apps/daemon/src/core/repos/profiles.ts +0 -83
- package/apps/daemon/src/core/repos/providerModels.ts +0 -58
- package/apps/daemon/src/core/repos/providerState.ts +0 -37
- package/apps/daemon/src/core/repos/secrets.ts +0 -145
- package/apps/daemon/src/core/repos/skillMeta.ts +0 -49
- package/apps/daemon/src/core/repos/triggers.ts +0 -101
- package/apps/daemon/src/core/repos/webTokens.ts +0 -87
- package/apps/daemon/src/core/secrets.ts +0 -65
- package/apps/daemon/src/core/services.ts +0 -264
- package/apps/daemon/src/core/skills/discover.ts +0 -28
- package/apps/daemon/src/core/skills/import.ts +0 -136
- package/apps/daemon/src/core/skills/parse.ts +0 -52
- package/apps/daemon/src/core/skills/resolve.ts +0 -50
- package/apps/daemon/src/index.ts +0 -45
- package/apps/daemon/src/lib/agent-cancel.ts +0 -48
- package/apps/daemon/src/lib/agent-id.ts +0 -13
- package/apps/daemon/src/lib/agent-turn.ts +0 -56
- package/apps/daemon/src/lib/api-key.ts +0 -56
- package/apps/daemon/src/lib/auth.ts +0 -41
- package/apps/daemon/src/lib/cron.ts +0 -93
- package/apps/daemon/src/lib/ctx.ts +0 -80
- package/apps/daemon/src/lib/messaging-host.ts +0 -34
- package/apps/daemon/src/lib/middleware-auth.ts +0 -52
- package/apps/daemon/src/lib/scheduler.ts +0 -294
- package/apps/daemon/src/routes/agents.ts +0 -772
- package/apps/daemon/src/routes/auth-login.ts +0 -193
- package/apps/daemon/src/routes/config.ts +0 -267
- package/apps/daemon/src/routes/groups.ts +0 -133
- package/apps/daemon/src/routes/messages.ts +0 -29
- package/apps/daemon/src/routes/misc.ts +0 -239
- package/apps/daemon/src/routes/profiles.ts +0 -197
- package/apps/daemon/src/routes/skills.ts +0 -123
- package/apps/daemon/src/routes/triggers.ts +0 -29
- package/apps/daemon/src/runtime/auth/openai-codex.ts +0 -121
- package/apps/daemon/src/runtime/auto-reply/heartbeat.ts +0 -31
- package/apps/daemon/src/runtime/index.ts +0 -77
- package/apps/daemon/src/runtime/memory/files.ts +0 -103
- package/apps/daemon/src/runtime/memory/qmd.ts +0 -152
- package/apps/daemon/src/runtime/memory/types.ts +0 -16
- package/apps/daemon/src/runtime/pi/events.ts +0 -173
- package/apps/daemon/src/runtime/pi/session.ts +0 -536
- package/apps/daemon/src/runtime/pi/tools.ts +0 -85
- package/apps/daemon/src/runtime/providers/catalog.ts +0 -145
- package/apps/daemon/src/runtime/providers/pi-adapter.ts +0 -272
- package/apps/daemon/src/runtime/providers/registry.ts +0 -374
- package/apps/daemon/src/runtime/providers/retry.ts +0 -176
- package/apps/daemon/src/runtime/providers/types.ts +0 -33
- package/apps/daemon/src/runtime/session/prompt.ts +0 -83
- package/apps/daemon/src/runtime/tools/bootstrap.ts +0 -22
- package/apps/daemon/src/runtime/tools/home.ts +0 -114
- package/apps/daemon/src/runtime/tools/memory.ts +0 -81
- package/apps/daemon/src/runtime/tools/messaging.ts +0 -127
- package/apps/daemon/src/runtime/tools/registry.ts +0 -29
- package/apps/daemon/src/runtime/tools/types.ts +0 -13
- package/apps/daemon/src/runtime/tools/web-extract.ts +0 -110
- package/apps/daemon/src/runtime/tools/web-ssrf.ts +0 -245
- package/apps/daemon/src/runtime/tools/web.ts +0 -273
- package/apps/daemon/src/runtime/worker/entry.ts +0 -221
- package/apps/daemon/src/runtime/worker/ipc-protocol.ts +0 -75
- package/apps/daemon/src/runtime/worker/spawn.ts +0 -249
- package/apps/daemon/test/core/agents.test.ts +0 -319
- package/apps/daemon/test/core/available-models.test.ts +0 -63
- package/apps/daemon/test/core/config.test.ts +0 -99
- package/apps/daemon/test/core/groups.test.ts +0 -63
- package/apps/daemon/test/core/helpers.ts +0 -50
- package/apps/daemon/test/core/identity.test.ts +0 -85
- package/apps/daemon/test/core/migrations.test.ts +0 -83
- package/apps/daemon/test/core/profiles.test.ts +0 -182
- package/apps/daemon/test/core/provider-models.test.ts +0 -57
- package/apps/daemon/test/core/provider-state.test.ts +0 -36
- package/apps/daemon/test/core/skill-meta.test.ts +0 -45
- package/apps/daemon/test/core/skills.test.ts +0 -271
- package/apps/daemon/test/core/triggers.test.ts +0 -182
- package/apps/daemon/test/core/web-tokens.test.ts +0 -79
- package/apps/daemon/test/cron.test.ts +0 -90
- package/apps/daemon/test/runtime/heartbeat.test.ts +0 -34
- package/apps/daemon/test/runtime/memory-qmd.test.ts +0 -97
- package/apps/daemon/test/runtime/memory.test.ts +0 -78
- package/apps/daemon/test/runtime/messaging.test.ts +0 -213
- package/apps/daemon/test/runtime/mock-server.ts +0 -65
- package/apps/daemon/test/runtime/openai-codex-auth.test.ts +0 -116
- package/apps/daemon/test/runtime/providers.test.ts +0 -306
- package/apps/daemon/test/runtime/retry.test.ts +0 -191
- package/apps/daemon/test/runtime/session-head.test.ts +0 -90
- package/apps/daemon/test/runtime/tools-home.test.ts +0 -102
- package/apps/daemon/test/runtime/tools-web.test.ts +0 -206
- package/apps/daemon/tsconfig.json +0 -4
- package/apps/mobile/README.md +0 -60
- package/apps/mobile/app/_layout.tsx +0 -58
- package/apps/mobile/app/agents/[id]/chat.tsx +0 -486
- package/apps/mobile/app/agents/[id]/index.tsx +0 -166
- package/apps/mobile/app/agents/index.tsx +0 -212
- package/apps/mobile/app/index.tsx +0 -21
- package/apps/mobile/app/pair.tsx +0 -226
- package/apps/mobile/app/settings.tsx +0 -419
- package/apps/mobile/app.json +0 -49
- package/apps/mobile/assets/adaptive-icon.png +0 -0
- package/apps/mobile/assets/favicon.png +0 -0
- package/apps/mobile/assets/icon.png +0 -0
- package/apps/mobile/assets/splash-icon.png +0 -0
- package/apps/mobile/babel.config.js +0 -6
- package/apps/mobile/metro.config.js +0 -28
- package/apps/mobile/package.json +0 -44
- package/apps/mobile/src/auth.ts +0 -66
- package/apps/mobile/src/pair-url.ts +0 -48
- package/apps/mobile/src/theme-context.tsx +0 -88
- package/apps/mobile/src/theme.ts +0 -135
- package/apps/mobile/test/pair-url.test.ts +0 -46
- package/apps/mobile/tsconfig.json +0 -23
- package/apps/web/components.json +0 -25
- package/apps/web/package.json +0 -39
- package/apps/web/public/baziu.svg +0 -8
- package/apps/web/src/components/AgentTabs.tsx +0 -45
- package/apps/web/src/components/BaziuLogo.tsx +0 -21
- package/apps/web/src/components/ChatPane.tsx +0 -1033
- package/apps/web/src/components/ConfigTabs.tsx +0 -29
- package/apps/web/src/components/CopyButton.tsx +0 -68
- package/apps/web/src/components/CreateGroupDialog.tsx +0 -127
- package/apps/web/src/components/FieldRow.tsx +0 -94
- package/apps/web/src/components/Footer.tsx +0 -10
- package/apps/web/src/components/PawIcon.tsx +0 -15
- package/apps/web/src/components/Sidebar.tsx +0 -287
- package/apps/web/src/components/SpawnDialog.tsx +0 -129
- package/apps/web/src/components/ThemeToggle.tsx +0 -75
- package/apps/web/src/components/TopNav.tsx +0 -34
- package/apps/web/src/components/ui/button.tsx +0 -67
- package/apps/web/src/components/ui/card.tsx +0 -103
- package/apps/web/src/components/ui/checkbox.tsx +0 -31
- package/apps/web/src/components/ui/dialog.tsx +0 -168
- package/apps/web/src/components/ui/input.tsx +0 -19
- package/apps/web/src/components/ui/label.tsx +0 -22
- package/apps/web/src/components/ui/radio-group.tsx +0 -44
- package/apps/web/src/components/ui/select.tsx +0 -192
- package/apps/web/src/components/ui/separator.tsx +0 -26
- package/apps/web/src/components/ui/table.tsx +0 -116
- package/apps/web/src/components/ui/tabs.tsx +0 -88
- package/apps/web/src/components/ui/textarea.tsx +0 -18
- package/apps/web/src/lib/auth.ts +0 -50
- package/apps/web/src/lib/daemon-client.ts +0 -34
- package/apps/web/src/lib/md.ts +0 -45
- package/apps/web/src/lib/utils.ts +0 -6
- package/apps/web/src/lib/wire-constants.ts +0 -27
- package/apps/web/src/routeTree.gen.ts +0 -408
- package/apps/web/src/router.tsx +0 -20
- package/apps/web/src/routes/__root.tsx +0 -123
- package/apps/web/src/routes/agents/$id/inbox.tsx +0 -207
- package/apps/web/src/routes/agents/$id/index.tsx +0 -527
- package/apps/web/src/routes/agents/$id/triggers.tsx +0 -239
- package/apps/web/src/routes/agents/index.tsx +0 -265
- package/apps/web/src/routes/api/$.ts +0 -88
- package/apps/web/src/routes/config/index.tsx +0 -315
- package/apps/web/src/routes/config/services.tsx +0 -49
- package/apps/web/src/routes/config/tokens.tsx +0 -192
- package/apps/web/src/routes/groups/$id/index.tsx +0 -153
- package/apps/web/src/routes/groups/$id/memory.tsx +0 -321
- package/apps/web/src/routes/groups/index.tsx +0 -191
- package/apps/web/src/routes/index.tsx +0 -133
- package/apps/web/src/routes/login.tsx +0 -63
- package/apps/web/src/routes/profiles/$id.tsx +0 -549
- package/apps/web/src/routes/profiles/index.tsx +0 -458
- package/apps/web/src/routes/skills/index.tsx +0 -297
- package/apps/web/src/routes/welcome.tsx +0 -61
- package/apps/web/src/styles.css +0 -449
- package/apps/web/tsconfig.json +0 -25
- package/apps/web/vite.config.ts +0 -25
- package/biome.json +0 -23
- package/docs/agent-engine.md +0 -219
- package/docs/architecture.md +0 -627
- package/docs/backlog/README.md +0 -42
- package/docs/backlog/draft/BAZ-001-a2a-federation-spike.md +0 -125
- package/docs/openclaw-reference.md +0 -210
- package/packages/api-types/package.json +0 -11
- package/packages/api-types/src/entities.ts +0 -146
- package/packages/api-types/src/events.ts +0 -55
- package/packages/api-types/src/index.ts +0 -488
- package/packages/api-types/src/memory.ts +0 -15
- package/packages/client/package.json +0 -13
- package/packages/client/src/index.ts +0 -117
- package/pnpm-workspace.yaml +0 -3
- package/tsconfig.base.json +0 -23
- package/tsconfig.json +0 -11
- package/vitest.config.ts +0 -22
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import type { Group, Profile } from '@bazilion/api-types'
|
|
2
|
-
import { isSetupComplete, listAvailableModels } from '../availableModels.ts'
|
|
3
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
4
|
-
import { registerGroup } from '../group/register.ts'
|
|
5
|
-
import type { Paths } from '../paths.ts'
|
|
6
|
-
import * as groupRepo from '../repos/groups.ts'
|
|
7
|
-
import * as profileRepo from '../repos/profiles.ts'
|
|
8
|
-
import { createProfile } from './create.ts'
|
|
9
|
-
|
|
10
|
-
export const DEFAULT_PROFILE_ID = 'default'
|
|
11
|
-
export const DEFAULT_GROUP_ID = 'default'
|
|
12
|
-
|
|
13
|
-
export interface SeedDefaultsInput {
|
|
14
|
-
/** `provider:model` used as the profile's defaultModel. */
|
|
15
|
-
model: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface SeedResult {
|
|
19
|
-
profile: Profile
|
|
20
|
-
group: Group
|
|
21
|
-
/** true if the helper created the profile this call (vs. returned an existing one). */
|
|
22
|
-
profileCreated: boolean
|
|
23
|
-
/** true if the helper created the group this call. */
|
|
24
|
-
groupCreated: boolean
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Seed the on-disk + DB defaults users land on after finishing first-run setup:
|
|
29
|
-
* a `default` group at `~/.bazilion/groups/default/` and a `default` profile
|
|
30
|
-
* wired to the just-enabled model. Fresh agents spawned from the default
|
|
31
|
-
* profile land in the default group unless another is specified.
|
|
32
|
-
*
|
|
33
|
-
* Idempotent: re-seeding reuses whichever pieces already exist, so it's safe
|
|
34
|
-
* to call whenever the setup state changes.
|
|
35
|
-
*/
|
|
36
|
-
export function seedDefaults(db: BazilionDb, paths: Paths, input: SeedDefaultsInput): SeedResult {
|
|
37
|
-
let group = groupRepo.get(db, DEFAULT_GROUP_ID, paths)
|
|
38
|
-
let groupCreated = false
|
|
39
|
-
if (!group) {
|
|
40
|
-
group = registerGroup(db, { id: DEFAULT_GROUP_ID, name: 'Default' }, paths)
|
|
41
|
-
groupCreated = true
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let profile = profileRepo.get(db, DEFAULT_PROFILE_ID)
|
|
45
|
-
let profileCreated = false
|
|
46
|
-
if (!profile) {
|
|
47
|
-
// skillsMode='all' so freshly-spawned default agents inherit every
|
|
48
|
-
// installed skill — the friendlier first-run posture. Custom profiles
|
|
49
|
-
// still default to 'selected' (createProfile's own default).
|
|
50
|
-
profile = createProfile(db, paths, {
|
|
51
|
-
id: DEFAULT_PROFILE_ID,
|
|
52
|
-
name: 'Default',
|
|
53
|
-
defaultModel: input.model,
|
|
54
|
-
skillsMode: 'all',
|
|
55
|
-
})
|
|
56
|
-
profileCreated = true
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return { profile, group, profileCreated, groupCreated }
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Safe to call from any endpoint that can change setup state (toggling a
|
|
64
|
-
* provider, editing model lists). No-op when either setup isn't complete
|
|
65
|
-
* (nothing to seed against yet) or the default profile already exists.
|
|
66
|
-
* Returns the seed result only on the cold-start transition.
|
|
67
|
-
*/
|
|
68
|
-
export function ensureSetupSeeded(db: BazilionDb, paths: Paths): SeedResult | null {
|
|
69
|
-
if (!isSetupComplete(db)) return null
|
|
70
|
-
if (profileRepo.get(db, DEFAULT_PROFILE_ID)) return null
|
|
71
|
-
const first = listAvailableModels(db)[0]
|
|
72
|
-
if (!first) return null
|
|
73
|
-
return seedDefaults(db, paths, { model: first.value })
|
|
74
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_SOUL = `# SOUL.md — Who You Are
|
|
2
|
-
|
|
3
|
-
This is your personality and operating principles. Edit it freely to make this agent yours.
|
|
4
|
-
|
|
5
|
-
## Core
|
|
6
|
-
- Be genuinely helpful, not performatively helpful.
|
|
7
|
-
- Have opinions. Push back when you disagree.
|
|
8
|
-
- Be resourceful before asking — read the file, check context, then ask if stuck.
|
|
9
|
-
|
|
10
|
-
## Boundaries
|
|
11
|
-
- Private things stay private.
|
|
12
|
-
- Confirm before destructive or external actions.
|
|
13
|
-
- You're a guest in someone's environment. Treat it with respect.
|
|
14
|
-
`
|
|
15
|
-
|
|
16
|
-
export const DEFAULT_IDENTITY = `# IDENTITY.md — Who Am I?
|
|
17
|
-
|
|
18
|
-
Fill this in during your first conversation. Make it yours.
|
|
19
|
-
|
|
20
|
-
- **Name:**
|
|
21
|
-
- **Vibe:**
|
|
22
|
-
- **Emoji:**
|
|
23
|
-
`
|
|
24
|
-
|
|
25
|
-
export const DEFAULT_BOOTSTRAP = `# BOOTSTRAP.md — First Run
|
|
26
|
-
|
|
27
|
-
You just woke up. There is no memory yet — that's normal.
|
|
28
|
-
|
|
29
|
-
## What to do
|
|
30
|
-
1. Ask your human who they are and what they want to call you.
|
|
31
|
-
2. Call the \`home_write\` tool with \`file: "IDENTITY.md"\` and new content that captures your name, vibe, and emoji. Do NOT use the generic \`edit\` / \`write\` tools for this — those land in your workspace, not your private home, and would collide with other agents.
|
|
32
|
-
3. Call \`bootstrap_done\` when finished — it removes this file so it does not appear in future sessions.
|
|
33
|
-
`
|
|
34
|
-
|
|
35
|
-
export const DEFAULT_AGENTS = `# AGENTS.md — Peers & Routing
|
|
36
|
-
|
|
37
|
-
Document the other agents you can reach and when to involve them. If you're
|
|
38
|
-
the only agent in this workspace, leave this short or delete it.
|
|
39
|
-
|
|
40
|
-
## Peers
|
|
41
|
-
- (name): what they're good at, when to hand off
|
|
42
|
-
`
|
|
43
|
-
|
|
44
|
-
export const DEFAULT_TOOLS = `# TOOLS.md — Tool Playbook
|
|
45
|
-
|
|
46
|
-
Notes on tool usage patterns that are specific to this agent. Keep generic
|
|
47
|
-
tool docs out — those live in SOUL.md or come from the tool descriptions.
|
|
48
|
-
|
|
49
|
-
## Patterns
|
|
50
|
-
- (pattern): when to use, what to avoid
|
|
51
|
-
`
|
|
52
|
-
|
|
53
|
-
export const DEFAULT_HEARTBEAT = `# HEARTBEAT.md — Scheduled Wake-Ups
|
|
54
|
-
|
|
55
|
-
Tasks the agent should check on every heartbeat. Leave empty (or commented)
|
|
56
|
-
to opt out — an empty file means "nothing to do right now".
|
|
57
|
-
|
|
58
|
-
## Tasks
|
|
59
|
-
- (task): cadence, exit criteria
|
|
60
|
-
`
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { writeFileSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import type { Profile, SkillsMode } from '@bazilion/api-types'
|
|
4
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
5
|
-
import type { Paths } from '../paths.ts'
|
|
6
|
-
import * as profileRepo from '../repos/profiles.ts'
|
|
7
|
-
|
|
8
|
-
export interface UpdateProfileInput {
|
|
9
|
-
name?: string
|
|
10
|
-
defaultModel?: string
|
|
11
|
-
skillsMode?: SkillsMode
|
|
12
|
-
defaultSkills?: string[]
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Update the mutable settings in profile.json + the DB row in lockstep.
|
|
17
|
-
* Profile files (SOUL/IDENTITY/BOOTSTRAP) and the memory backend are NOT
|
|
18
|
-
* touched — those have their own paths.
|
|
19
|
-
*/
|
|
20
|
-
export function updateProfile(
|
|
21
|
-
db: BazilionDb,
|
|
22
|
-
paths: Paths,
|
|
23
|
-
id: string,
|
|
24
|
-
input: UpdateProfileInput,
|
|
25
|
-
): Profile {
|
|
26
|
-
const existing = profileRepo.get(db, id)
|
|
27
|
-
if (!existing) throw new Error(`profile not found: ${id}`)
|
|
28
|
-
|
|
29
|
-
const nextSkillsMode: SkillsMode = input.skillsMode ?? existing.skillsMode
|
|
30
|
-
|
|
31
|
-
const next = {
|
|
32
|
-
name: input.name ?? existing.name,
|
|
33
|
-
defaultModel: input.defaultModel ?? existing.defaultModel,
|
|
34
|
-
skillsMode: nextSkillsMode,
|
|
35
|
-
}
|
|
36
|
-
profileRepo.update(db, id, next)
|
|
37
|
-
|
|
38
|
-
if (input.defaultSkills !== undefined) {
|
|
39
|
-
profileRepo.setDefaultSkills(db, id, input.defaultSkills)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const skills = profileRepo.getDefaultSkills(db, id)
|
|
43
|
-
const profileJson = {
|
|
44
|
-
name: next.name,
|
|
45
|
-
defaultModel: next.defaultModel,
|
|
46
|
-
skillsMode: next.skillsMode,
|
|
47
|
-
defaultSkills: skills,
|
|
48
|
-
}
|
|
49
|
-
writeFileSync(
|
|
50
|
-
join(paths.profileDir(id), 'profile.json'),
|
|
51
|
-
`${JSON.stringify(profileJson, null, 2)}\n`,
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
const updated = profileRepo.get(db, id)
|
|
55
|
-
if (!updated) throw new Error(`profile vanished after update: ${id}`)
|
|
56
|
-
return updated
|
|
57
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
const SLUG = /^[a-z0-9][a-z0-9-]*$/
|
|
2
|
-
|
|
3
|
-
export function validateSlug(s: string): void {
|
|
4
|
-
if (!SLUG.test(s)) {
|
|
5
|
-
throw new Error(
|
|
6
|
-
`invalid slug "${s}": must match /^[a-z0-9][a-z0-9-]*$/ (lowercase letters, digits, hyphens; must start with letter or digit)`,
|
|
7
|
-
)
|
|
8
|
-
}
|
|
9
|
-
}
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import type { Agent, AgentSkillAttachment, AgentStatus, ReasoningLevel } from '@bazilion/api-types'
|
|
2
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
3
|
-
|
|
4
|
-
interface RawAgent {
|
|
5
|
-
id: string
|
|
6
|
-
profile_id: string
|
|
7
|
-
name: string
|
|
8
|
-
model_override: string | null
|
|
9
|
-
reasoning_level: string
|
|
10
|
-
status: string
|
|
11
|
-
dir: string
|
|
12
|
-
group_id: string
|
|
13
|
-
created_at: number
|
|
14
|
-
archived_at: number | null
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function toAgent(r: RawAgent): Agent {
|
|
18
|
-
return {
|
|
19
|
-
id: r.id,
|
|
20
|
-
profileId: r.profile_id,
|
|
21
|
-
name: r.name,
|
|
22
|
-
modelOverride: r.model_override,
|
|
23
|
-
reasoningLevel: r.reasoning_level as ReasoningLevel,
|
|
24
|
-
status: r.status as AgentStatus,
|
|
25
|
-
dir: r.dir,
|
|
26
|
-
groupId: r.group_id,
|
|
27
|
-
createdAt: r.created_at,
|
|
28
|
-
archivedAt: r.archived_at,
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function insert(db: BazilionDb, a: Omit<Agent, 'createdAt' | 'archivedAt'>): Agent {
|
|
33
|
-
const now = Date.now()
|
|
34
|
-
db.raw.run(
|
|
35
|
-
`INSERT INTO agents (id, profile_id, name, model_override, reasoning_level, status, dir, group_id, created_at, archived_at)
|
|
36
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`,
|
|
37
|
-
[a.id, a.profileId, a.name, a.modelOverride, a.reasoningLevel, a.status, a.dir, a.groupId, now],
|
|
38
|
-
)
|
|
39
|
-
return { ...a, createdAt: now, archivedAt: null }
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function setReasoningLevel(db: BazilionDb, id: string, level: ReasoningLevel): void {
|
|
43
|
-
db.raw.run('UPDATE agents SET reasoning_level = ? WHERE id = ?', [level, id])
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function setModelOverride(db: BazilionDb, id: string, model: string | null): void {
|
|
47
|
-
db.raw.run('UPDATE agents SET model_override = ? WHERE id = ?', [model, id])
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function setName(db: BazilionDb, id: string, name: string): void {
|
|
51
|
-
db.raw.run('UPDATE agents SET name = ? WHERE id = ?', [name, id])
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** Move the agent to a different group. The new group must exist. */
|
|
55
|
-
export function setGroup(db: BazilionDb, id: string, groupId: string): void {
|
|
56
|
-
db.raw.run('UPDATE agents SET group_id = ? WHERE id = ?', [groupId, id])
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Lookup by full UUID, exact name, or unambiguous UUID prefix (git-style
|
|
61
|
-
* shorthand). Resolution order: (1) exact id, (2) exact name — only if
|
|
62
|
-
* unique — (3) ≥4-char id prefix — only if unique. Ambiguous name or prefix
|
|
63
|
-
* returns null so the caller's "not found" branch fires. Internal callers
|
|
64
|
-
* always pass full UUIDs, so this only exercises on the new path (URL params,
|
|
65
|
-
* CLI arguments).
|
|
66
|
-
*
|
|
67
|
-
* Name comes before prefix so that a hex-looking name like "abcd1234" resolves
|
|
68
|
-
* to the named agent rather than accidentally matching a UUID prefix.
|
|
69
|
-
*/
|
|
70
|
-
export function get(db: BazilionDb, idOrName: string): Agent | null {
|
|
71
|
-
if (!idOrName) return null
|
|
72
|
-
const exactId = db.raw
|
|
73
|
-
.query<RawAgent, [string]>('SELECT * FROM agents WHERE id = ?')
|
|
74
|
-
.get(idOrName)
|
|
75
|
-
if (exactId) return toAgent(exactId)
|
|
76
|
-
const byName = db.raw
|
|
77
|
-
.query<RawAgent, [string]>('SELECT * FROM agents WHERE name = ? LIMIT 2')
|
|
78
|
-
.all(idOrName)
|
|
79
|
-
if (byName.length === 1 && byName[0]) return toAgent(byName[0])
|
|
80
|
-
if (byName.length > 1) return null
|
|
81
|
-
if (idOrName.length < 4) return null
|
|
82
|
-
const byPrefix = db.raw
|
|
83
|
-
.query<RawAgent, [string]>('SELECT * FROM agents WHERE id LIKE ? LIMIT 2')
|
|
84
|
-
.all(`${idOrName}%`)
|
|
85
|
-
return byPrefix.length === 1 && byPrefix[0] ? toAgent(byPrefix[0]) : null
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Resolve `idOrPrefix` to a full agent ID, or null if not found / ambiguous.
|
|
90
|
-
* Thin wrapper around `get` for callers that want the canonical ID without
|
|
91
|
-
* the rest of the row (e.g. URL param normalization).
|
|
92
|
-
*/
|
|
93
|
-
export function resolveId(db: BazilionDb, idOrPrefix: string): string | null {
|
|
94
|
-
return get(db, idOrPrefix)?.id ?? null
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function list(db: BazilionDb, opts?: { includeArchived?: boolean }): Agent[] {
|
|
98
|
-
const sql = opts?.includeArchived
|
|
99
|
-
? 'SELECT * FROM agents ORDER BY created_at ASC'
|
|
100
|
-
: "SELECT * FROM agents WHERE status != 'archived' ORDER BY created_at ASC"
|
|
101
|
-
return db.raw.query<RawAgent, []>(sql).all().map(toAgent)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function countByProfile(db: BazilionDb, profileId: string): number {
|
|
105
|
-
return (
|
|
106
|
-
db.raw
|
|
107
|
-
.query<{ c: number }, [string]>('SELECT COUNT(*) as c FROM agents WHERE profile_id = ?')
|
|
108
|
-
.get(profileId)?.c ?? 0
|
|
109
|
-
)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Count agents whose group_id matches. Blocks group deletion when > 0 (the
|
|
114
|
-
* `agents.group_id` FK is `ON DELETE RESTRICT` — members must be moved or
|
|
115
|
-
* archived before a group can go away).
|
|
116
|
-
*/
|
|
117
|
-
export function countByGroup(db: BazilionDb, groupId: string): number {
|
|
118
|
-
return (
|
|
119
|
-
db.raw
|
|
120
|
-
.query<{ c: number }, [string]>('SELECT COUNT(*) as c FROM agents WHERE group_id = ?')
|
|
121
|
-
.get(groupId)?.c ?? 0
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function setStatus(db: BazilionDb, id: string, status: AgentStatus): void {
|
|
126
|
-
db.raw.run('UPDATE agents SET status = ? WHERE id = ?', [status, id])
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export function archive(db: BazilionDb, id: string): void {
|
|
130
|
-
db.raw.run("UPDATE agents SET status = 'archived', archived_at = ? WHERE id = ?", [
|
|
131
|
-
Date.now(),
|
|
132
|
-
id,
|
|
133
|
-
])
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function unarchive(db: BazilionDb, id: string): void {
|
|
137
|
-
db.raw.run("UPDATE agents SET status = 'idle', archived_at = NULL WHERE id = ?", [id])
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function remove(db: BazilionDb, id: string): void {
|
|
141
|
-
db.raw.run('DELETE FROM agents WHERE id = ?', [id])
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// --- skill attachments ---
|
|
145
|
-
|
|
146
|
-
interface RawSkill {
|
|
147
|
-
agent_id: string
|
|
148
|
-
skill_name: string
|
|
149
|
-
attached_at: number
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function toSkillAttachment(r: RawSkill): AgentSkillAttachment {
|
|
153
|
-
return {
|
|
154
|
-
agentId: r.agent_id,
|
|
155
|
-
skillName: r.skill_name,
|
|
156
|
-
attachedAt: r.attached_at,
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export function attachSkill(
|
|
161
|
-
db: BazilionDb,
|
|
162
|
-
agentId: string,
|
|
163
|
-
skillName: string,
|
|
164
|
-
): AgentSkillAttachment {
|
|
165
|
-
const now = Date.now()
|
|
166
|
-
db.raw.run(
|
|
167
|
-
`INSERT INTO agent_skills (agent_id, skill_name, attached_at)
|
|
168
|
-
VALUES (?, ?, ?)
|
|
169
|
-
ON CONFLICT (agent_id, skill_name) DO NOTHING`,
|
|
170
|
-
[agentId, skillName, now],
|
|
171
|
-
)
|
|
172
|
-
return { agentId, skillName, attachedAt: now }
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export function detachSkill(db: BazilionDb, agentId: string, skillName: string): void {
|
|
176
|
-
db.raw.run('DELETE FROM agent_skills WHERE agent_id = ? AND skill_name = ?', [agentId, skillName])
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export function listAttachedSkills(db: BazilionDb, agentId: string): string[] {
|
|
180
|
-
return db.raw
|
|
181
|
-
.query<{ skill_name: string }, [string]>(
|
|
182
|
-
'SELECT skill_name FROM agent_skills WHERE agent_id = ? ORDER BY attached_at ASC',
|
|
183
|
-
)
|
|
184
|
-
.all(agentId)
|
|
185
|
-
.map((r) => r.skill_name)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export function listSkillAttachments(db: BazilionDb, agentId: string): AgentSkillAttachment[] {
|
|
189
|
-
return db.raw
|
|
190
|
-
.query<RawSkill, [string]>(
|
|
191
|
-
'SELECT * FROM agent_skills WHERE agent_id = ? ORDER BY attached_at ASC',
|
|
192
|
-
)
|
|
193
|
-
.all(agentId)
|
|
194
|
-
.map(toSkillAttachment)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// --- chat history snapshot ---
|
|
198
|
-
//
|
|
199
|
-
// Conversation transcript storage lives in pi-coding-agent's SessionManager
|
|
200
|
-
// (JSONL under `~/.bazilion/agents/<id>/sessions/<sessionId>.jsonl`).
|
|
201
|
-
// Clear/truncate/rotate operations go through the runtime's
|
|
202
|
-
// `apps/daemon/src/runtime/pi/session.ts` helpers, not repo-level accessors.
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// Plaintext config store, backed by the `config` table.
|
|
2
|
-
//
|
|
3
|
-
// Companion to `secrets.ts` — same key-shaped values, but for the ones that
|
|
4
|
-
// don't need confidentiality (server URLs, region slugs, project IDs). Kept
|
|
5
|
-
// separate so the /config UI can show plaintext values directly without
|
|
6
|
-
// extra masking logic.
|
|
7
|
-
//
|
|
8
|
-
// The CONFIG_KEYS allowlist (derived from the services registry) is enforced
|
|
9
|
-
// here on writes — a typo or accidental misclassification can't put an API
|
|
10
|
-
// key in this table.
|
|
11
|
-
|
|
12
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
13
|
-
import { SERVICES } from '../services.ts'
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Env var names that live in the plaintext config store. Derived from the
|
|
17
|
-
* services registry — any field marked `kind: 'config'` ends up here.
|
|
18
|
-
*/
|
|
19
|
-
export const CONFIG_KEYS: readonly string[] = SERVICES.flatMap((s) =>
|
|
20
|
-
s.fields.filter((f) => f.kind === 'config').map((f) => f.envVar),
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
const CONFIG_KEY_SET = new Set<string>(CONFIG_KEYS)
|
|
24
|
-
|
|
25
|
-
export function isConfigKey(key: string): boolean {
|
|
26
|
-
return CONFIG_KEY_SET.has(key)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface RawRow {
|
|
30
|
-
key: string
|
|
31
|
-
value: string
|
|
32
|
-
updated_at: number
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface ConfigStore {
|
|
36
|
-
get(key: string): string | undefined
|
|
37
|
-
set(key: string, value: string): void
|
|
38
|
-
remove(key: string): void
|
|
39
|
-
list(): { key: string; value: string }[]
|
|
40
|
-
getAll(): Record<string, string>
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function openConfig(db: BazilionDb): ConfigStore {
|
|
44
|
-
return {
|
|
45
|
-
get(key) {
|
|
46
|
-
const row = db.raw.query<RawRow, [string]>('SELECT * FROM config WHERE key = ?').get(key)
|
|
47
|
-
return row?.value
|
|
48
|
-
},
|
|
49
|
-
set(key, value) {
|
|
50
|
-
if (!isConfigKey(key)) {
|
|
51
|
-
throw new Error(
|
|
52
|
-
`config.set: "${key}" is not a known config key (${CONFIG_KEYS.join(', ')})`,
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
db.raw.run(
|
|
56
|
-
`INSERT INTO config (key, value, updated_at) VALUES (?, ?, ?)
|
|
57
|
-
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,
|
|
58
|
-
[key, value, Date.now()],
|
|
59
|
-
)
|
|
60
|
-
},
|
|
61
|
-
remove(key) {
|
|
62
|
-
db.raw.run('DELETE FROM config WHERE key = ?', [key])
|
|
63
|
-
},
|
|
64
|
-
list() {
|
|
65
|
-
return db.raw
|
|
66
|
-
.query<RawRow, []>('SELECT * FROM config ORDER BY key ASC')
|
|
67
|
-
.all()
|
|
68
|
-
.map((r) => ({ key: r.key, value: r.value }))
|
|
69
|
-
},
|
|
70
|
-
getAll() {
|
|
71
|
-
const out: Record<string, string> = {}
|
|
72
|
-
for (const r of db.raw.query<RawRow, []>('SELECT * FROM config').all()) {
|
|
73
|
-
out[r.key] = r.value
|
|
74
|
-
}
|
|
75
|
-
return out
|
|
76
|
-
},
|
|
77
|
-
}
|
|
78
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// Groups repo. The group `id` is the slug AND the directory name under
|
|
2
|
-
// `~/.bazilion/groups/<slug>/`. There is no `path` column — callers
|
|
3
|
-
// derive `paths.groupDir(id)` at read time. That makes the on-disk path
|
|
4
|
-
// canonical: a real directory or a symlink, but always at the same slot.
|
|
5
|
-
|
|
6
|
-
import type { Group } from '@bazilion/api-types'
|
|
7
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
8
|
-
import type { Paths } from '../paths.ts'
|
|
9
|
-
|
|
10
|
-
interface RawGroup {
|
|
11
|
-
id: string
|
|
12
|
-
name: string
|
|
13
|
-
user_md: string
|
|
14
|
-
created_at: number
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function toGroup(r: RawGroup, paths: Paths): Group {
|
|
18
|
-
return {
|
|
19
|
-
id: r.id,
|
|
20
|
-
name: r.name,
|
|
21
|
-
path: paths.groupDir(r.id),
|
|
22
|
-
userMd: r.user_md,
|
|
23
|
-
createdAt: r.created_at,
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function insert(db: BazilionDb, g: { id: string; name: string }, paths: Paths): Group {
|
|
28
|
-
const now = Date.now()
|
|
29
|
-
db.raw.run("INSERT INTO groups (id, name, user_md, created_at) VALUES (?, ?, '', ?)", [
|
|
30
|
-
g.id,
|
|
31
|
-
g.name,
|
|
32
|
-
now,
|
|
33
|
-
])
|
|
34
|
-
return { id: g.id, name: g.name, path: paths.groupDir(g.id), userMd: '', createdAt: now }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function get(db: BazilionDb, id: string, paths: Paths): Group | null {
|
|
38
|
-
const row = db.raw.query<RawGroup, [string]>('SELECT * FROM groups WHERE id = ?').get(id)
|
|
39
|
-
return row ? toGroup(row, paths) : null
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function list(db: BazilionDb, paths: Paths): Group[] {
|
|
43
|
-
return db.raw
|
|
44
|
-
.query<RawGroup, []>('SELECT * FROM groups ORDER BY created_at ASC')
|
|
45
|
-
.all()
|
|
46
|
-
.map((r) => toGroup(r, paths))
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function remove(db: BazilionDb, id: string): void {
|
|
50
|
-
db.raw.run('DELETE FROM groups WHERE id = ?', [id])
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function setUserMd(db: BazilionDb, id: string, userMd: string): void {
|
|
54
|
-
db.raw.run('UPDATE groups SET user_md = ? WHERE id = ?', [userMd, id])
|
|
55
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto'
|
|
2
|
-
import type { Message } from '@bazilion/api-types'
|
|
3
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
4
|
-
|
|
5
|
-
interface RawMessage {
|
|
6
|
-
id: string
|
|
7
|
-
from_agent_id: string
|
|
8
|
-
to_agent_id: string
|
|
9
|
-
reply_to: string | null
|
|
10
|
-
payload: string
|
|
11
|
-
created_at: number
|
|
12
|
-
read_at: number | null
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function toMessage(r: RawMessage): Message {
|
|
16
|
-
return {
|
|
17
|
-
id: r.id,
|
|
18
|
-
fromAgentId: r.from_agent_id,
|
|
19
|
-
toAgentId: r.to_agent_id,
|
|
20
|
-
replyTo: r.reply_to,
|
|
21
|
-
payload: r.payload,
|
|
22
|
-
createdAt: r.created_at,
|
|
23
|
-
readAt: r.read_at,
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function send(
|
|
28
|
-
db: BazilionDb,
|
|
29
|
-
input: { from: string; to: string; payload: string; replyTo?: string | null },
|
|
30
|
-
): Message {
|
|
31
|
-
const id = randomUUID()
|
|
32
|
-
const now = Date.now()
|
|
33
|
-
db.raw.run(
|
|
34
|
-
`INSERT INTO messages (id, from_agent_id, to_agent_id, reply_to, payload, created_at, read_at)
|
|
35
|
-
VALUES (?, ?, ?, ?, ?, ?, NULL)`,
|
|
36
|
-
[id, input.from, input.to, input.replyTo ?? null, input.payload, now],
|
|
37
|
-
)
|
|
38
|
-
return {
|
|
39
|
-
id,
|
|
40
|
-
fromAgentId: input.from,
|
|
41
|
-
toAgentId: input.to,
|
|
42
|
-
replyTo: input.replyTo ?? null,
|
|
43
|
-
payload: input.payload,
|
|
44
|
-
createdAt: now,
|
|
45
|
-
readAt: null,
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function get(db: BazilionDb, id: string): Message | null {
|
|
50
|
-
const row = db.raw.query<RawMessage, [string]>('SELECT * FROM messages WHERE id = ?').get(id)
|
|
51
|
-
return row ? toMessage(row) : null
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function listInbox(
|
|
55
|
-
db: BazilionDb,
|
|
56
|
-
agentId: string,
|
|
57
|
-
opts?: { unreadOnly?: boolean },
|
|
58
|
-
): Message[] {
|
|
59
|
-
const sql = opts?.unreadOnly
|
|
60
|
-
? 'SELECT * FROM messages WHERE to_agent_id = ? AND read_at IS NULL ORDER BY created_at ASC'
|
|
61
|
-
: 'SELECT * FROM messages WHERE to_agent_id = ? ORDER BY created_at ASC'
|
|
62
|
-
return db.raw.query<RawMessage, [string]>(sql).all(agentId).map(toMessage)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function markRead(db: BazilionDb, id: string): void {
|
|
66
|
-
db.raw.run('UPDATE messages SET read_at = ? WHERE id = ? AND read_at IS NULL', [Date.now(), id])
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Find messages that are replies to a given message id, addressed to a specific agent.
|
|
71
|
-
* Used by `wait_for_reply` to poll for incoming responses.
|
|
72
|
-
*/
|
|
73
|
-
export function findReplies(db: BazilionDb, toAgentId: string, inReplyTo: string): Message[] {
|
|
74
|
-
return db.raw
|
|
75
|
-
.query<RawMessage, [string, string]>(
|
|
76
|
-
`SELECT * FROM messages
|
|
77
|
-
WHERE to_agent_id = ? AND reply_to = ?
|
|
78
|
-
ORDER BY created_at ASC`,
|
|
79
|
-
)
|
|
80
|
-
.all(toAgentId, inReplyTo)
|
|
81
|
-
.map(toMessage)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Return the distinct `to_agent_id`s that currently have at least one unread
|
|
86
|
-
* message, filtered to agents not in a terminal state (idle or starting).
|
|
87
|
-
* Used by the scheduler's message-wake loop so a tick can fan-out auto-
|
|
88
|
-
* delivery turns without walking every agent in the DB.
|
|
89
|
-
*/
|
|
90
|
-
export function listRecipientsWithUnread(db: BazilionDb): string[] {
|
|
91
|
-
const rows = db.raw
|
|
92
|
-
.query<{ to_agent_id: string }, []>(
|
|
93
|
-
`SELECT DISTINCT m.to_agent_id FROM messages m
|
|
94
|
-
JOIN agents a ON a.id = m.to_agent_id
|
|
95
|
-
WHERE m.read_at IS NULL AND a.status = 'idle'
|
|
96
|
-
ORDER BY m.to_agent_id`,
|
|
97
|
-
)
|
|
98
|
-
.all()
|
|
99
|
-
return rows.map((r) => r.to_agent_id)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Atomically fetch + mark-read all unread messages addressed to `agentId`.
|
|
104
|
-
* Runs inside a transaction so two concurrent schedulers / manual deliveries
|
|
105
|
-
* can't double-dispatch the same message. Returns the fetched messages in
|
|
106
|
-
* ascending `created_at` order — callers format them into the recipient's
|
|
107
|
-
* wake-up prompt.
|
|
108
|
-
*/
|
|
109
|
-
export function drainUnreadForAgent(db: BazilionDb, agentId: string): Message[] {
|
|
110
|
-
return db.raw.transaction(() => {
|
|
111
|
-
const rows = db.raw
|
|
112
|
-
.query<RawMessage, [string]>(
|
|
113
|
-
`SELECT * FROM messages
|
|
114
|
-
WHERE to_agent_id = ? AND read_at IS NULL
|
|
115
|
-
ORDER BY created_at ASC`,
|
|
116
|
-
)
|
|
117
|
-
.all(agentId)
|
|
118
|
-
if (rows.length === 0) return []
|
|
119
|
-
const now = Date.now()
|
|
120
|
-
db.raw.run(
|
|
121
|
-
`UPDATE messages SET read_at = ?
|
|
122
|
-
WHERE to_agent_id = ? AND read_at IS NULL`,
|
|
123
|
-
[now, agentId],
|
|
124
|
-
)
|
|
125
|
-
return rows.map((r) => toMessage({ ...r, read_at: now }))
|
|
126
|
-
})()
|
|
127
|
-
}
|