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,239 +0,0 @@
|
|
|
1
|
-
import { ApiClientError } from '@bazilion/client'
|
|
2
|
-
import type { AgentTrigger, ResolvedAgent } from '@bazilion/api-types'
|
|
3
|
-
import { createFileRoute, redirect, useRouter } from '@tanstack/react-router'
|
|
4
|
-
import { createServerFn } from '@tanstack/react-start'
|
|
5
|
-
import { useState } from 'react'
|
|
6
|
-
import { AgentTabs } from '../../../components/AgentTabs'
|
|
7
|
-
import { daemonClient } from '../../../lib/daemon-client'
|
|
8
|
-
|
|
9
|
-
interface TriggersView {
|
|
10
|
-
resolved: ResolvedAgent
|
|
11
|
-
triggers: AgentTrigger[]
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const fetchTriggers = createServerFn({ method: 'POST' })
|
|
15
|
-
.inputValidator((d: { id: string }) => d)
|
|
16
|
-
.handler(async ({ data }): Promise<TriggersView | null> => {
|
|
17
|
-
const c = daemonClient()
|
|
18
|
-
let resolved: ResolvedAgent
|
|
19
|
-
try {
|
|
20
|
-
resolved = await c.get<ResolvedAgent>(`/api/agents/${encodeURIComponent(data.id)}`)
|
|
21
|
-
} catch (err) {
|
|
22
|
-
if (err instanceof ApiClientError && err.status === 404) return null
|
|
23
|
-
throw err
|
|
24
|
-
}
|
|
25
|
-
const { triggers } = await c.get<{ triggers: AgentTrigger[] }>(
|
|
26
|
-
`/api/agents/${encodeURIComponent(resolved.agent.id)}/triggers`,
|
|
27
|
-
)
|
|
28
|
-
return { resolved, triggers }
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
export const Route = createFileRoute('/agents/$id/triggers')({
|
|
32
|
-
loader: async ({ params }) => {
|
|
33
|
-
const data = await fetchTriggers({ data: { id: params.id } })
|
|
34
|
-
if (!data) throw redirect({ to: '/agents' })
|
|
35
|
-
return data
|
|
36
|
-
},
|
|
37
|
-
component: TriggersPage,
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
function TriggersPage() {
|
|
41
|
-
const { resolved, triggers } = Route.useLoaderData()
|
|
42
|
-
const router = useRouter()
|
|
43
|
-
|
|
44
|
-
async function toggle(t: AgentTrigger) {
|
|
45
|
-
await fetch(`/api/triggers/${t.id}`, {
|
|
46
|
-
method: 'PATCH',
|
|
47
|
-
headers: { 'content-type': 'application/json' },
|
|
48
|
-
body: JSON.stringify({ enabled: !t.enabled }),
|
|
49
|
-
})
|
|
50
|
-
await router.invalidate()
|
|
51
|
-
}
|
|
52
|
-
async function del(id: string) {
|
|
53
|
-
if (!confirm('delete this trigger?')) return
|
|
54
|
-
await fetch(`/api/triggers/${id}`, { method: 'DELETE' })
|
|
55
|
-
await router.invalidate()
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<div>
|
|
60
|
-
<header className="mb-6">
|
|
61
|
-
<h1>{resolved.agent.name}</h1>
|
|
62
|
-
</header>
|
|
63
|
-
<AgentTabs
|
|
64
|
-
agentId={resolved.agent.id}
|
|
65
|
-
active="triggers"
|
|
66
|
-
archived={resolved.agent.status === 'archived'}
|
|
67
|
-
/>
|
|
68
|
-
|
|
69
|
-
<AddTriggerForm agentId={resolved.agent.id} onAdded={() => router.invalidate()} />
|
|
70
|
-
|
|
71
|
-
<h3 className="mb-3 mt-6 font-body text-[0.85em] font-semibold uppercase tracking-wider text-mocha-light">
|
|
72
|
-
Active triggers
|
|
73
|
-
</h3>
|
|
74
|
-
|
|
75
|
-
{triggers.length === 0 ? (
|
|
76
|
-
<p className="muted">no triggers yet — add one above.</p>
|
|
77
|
-
) : (
|
|
78
|
-
<table>
|
|
79
|
-
<thead>
|
|
80
|
-
<tr>
|
|
81
|
-
<th>id</th>
|
|
82
|
-
<th>kind</th>
|
|
83
|
-
<th>spec</th>
|
|
84
|
-
<th>message</th>
|
|
85
|
-
<th>last fired</th>
|
|
86
|
-
<th />
|
|
87
|
-
</tr>
|
|
88
|
-
</thead>
|
|
89
|
-
<tbody>
|
|
90
|
-
{triggers.map((t) => {
|
|
91
|
-
const spec = t.kind === 'interval' ? `every ${t.intervalSec}s` : t.cronExpr
|
|
92
|
-
const last = t.lastFiredAt ? new Date(t.lastFiredAt).toLocaleString() : '(never)'
|
|
93
|
-
return (
|
|
94
|
-
<tr key={t.id} className={t.enabled ? '' : 'opacity-60'}>
|
|
95
|
-
<td>
|
|
96
|
-
<code>{t.id.slice(0, 8)}…</code>
|
|
97
|
-
</td>
|
|
98
|
-
<td>
|
|
99
|
-
<span className="inline-block rounded-sm border border-frost bg-ivory px-2 py-0.5 font-mono text-[0.8em] text-mocha">
|
|
100
|
-
{t.kind}
|
|
101
|
-
</span>
|
|
102
|
-
</td>
|
|
103
|
-
<td>
|
|
104
|
-
<code>{spec}</code>
|
|
105
|
-
</td>
|
|
106
|
-
<td>
|
|
107
|
-
{t.message.length > 60 ? `${t.message.slice(0, 60)}…` : t.message}
|
|
108
|
-
</td>
|
|
109
|
-
<td className="text-[0.82em] text-mocha-light">{last}</td>
|
|
110
|
-
<td>
|
|
111
|
-
<div className="flex gap-1.5">
|
|
112
|
-
<button type="button" className="ghost-btn" onClick={() => toggle(t)}>
|
|
113
|
-
{t.enabled ? 'disable' : 'enable'}
|
|
114
|
-
</button>
|
|
115
|
-
<button type="button" className="ghost-btn" onClick={() => del(t.id)}>
|
|
116
|
-
delete
|
|
117
|
-
</button>
|
|
118
|
-
</div>
|
|
119
|
-
</td>
|
|
120
|
-
</tr>
|
|
121
|
-
)
|
|
122
|
-
})}
|
|
123
|
-
</tbody>
|
|
124
|
-
</table>
|
|
125
|
-
)}
|
|
126
|
-
</div>
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function AddTriggerForm({
|
|
131
|
-
agentId,
|
|
132
|
-
onAdded,
|
|
133
|
-
}: {
|
|
134
|
-
agentId: string
|
|
135
|
-
onAdded: () => void
|
|
136
|
-
}) {
|
|
137
|
-
const [kind, setKind] = useState<'interval' | 'cron'>('interval')
|
|
138
|
-
const [intervalSec, setIntervalSec] = useState(300)
|
|
139
|
-
const [cronExpr, setCronExpr] = useState('')
|
|
140
|
-
const [message, setMessage] = useState('')
|
|
141
|
-
const [err, setErr] = useState<string | null>(null)
|
|
142
|
-
const [submitting, setSubmitting] = useState(false)
|
|
143
|
-
|
|
144
|
-
async function submit(e: React.FormEvent<HTMLFormElement>) {
|
|
145
|
-
e.preventDefault()
|
|
146
|
-
setErr(null)
|
|
147
|
-
if (!message.trim()) {
|
|
148
|
-
setErr('message is required')
|
|
149
|
-
return
|
|
150
|
-
}
|
|
151
|
-
if (kind === 'interval' && (!Number.isFinite(intervalSec) || intervalSec <= 0)) {
|
|
152
|
-
setErr('interval must be a positive number')
|
|
153
|
-
return
|
|
154
|
-
}
|
|
155
|
-
if (kind === 'cron' && !cronExpr.trim()) {
|
|
156
|
-
setErr('cron expression is required')
|
|
157
|
-
return
|
|
158
|
-
}
|
|
159
|
-
setSubmitting(true)
|
|
160
|
-
try {
|
|
161
|
-
const body: Record<string, unknown> = { kind, message: message.trim() }
|
|
162
|
-
if (kind === 'interval') body.intervalSec = intervalSec
|
|
163
|
-
else body.cronExpr = cronExpr.trim()
|
|
164
|
-
const res = await fetch(`/api/agents/${encodeURIComponent(agentId)}/triggers`, {
|
|
165
|
-
method: 'POST',
|
|
166
|
-
headers: { 'content-type': 'application/json' },
|
|
167
|
-
body: JSON.stringify(body),
|
|
168
|
-
})
|
|
169
|
-
if (!res.ok) {
|
|
170
|
-
const e2 = (await res.json().catch(() => null)) as { error?: string } | null
|
|
171
|
-
throw new Error(e2?.error ?? res.statusText)
|
|
172
|
-
}
|
|
173
|
-
setMessage('')
|
|
174
|
-
setCronExpr('')
|
|
175
|
-
setIntervalSec(300)
|
|
176
|
-
onAdded()
|
|
177
|
-
} catch (e2) {
|
|
178
|
-
setErr((e2 as Error).message)
|
|
179
|
-
} finally {
|
|
180
|
-
setSubmitting(false)
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return (
|
|
185
|
-
<form className="card" onSubmit={submit}>
|
|
186
|
-
<h3>Add trigger</h3>
|
|
187
|
-
<div className="mb-3 flex gap-3">
|
|
188
|
-
<label className="m-0 inline-flex cursor-pointer items-center gap-1">
|
|
189
|
-
<input
|
|
190
|
-
type="radio"
|
|
191
|
-
checked={kind === 'interval'}
|
|
192
|
-
onChange={() => setKind('interval')}
|
|
193
|
-
/>
|
|
194
|
-
interval (every N seconds)
|
|
195
|
-
</label>
|
|
196
|
-
<label className="m-0 inline-flex cursor-pointer items-center gap-1">
|
|
197
|
-
<input type="radio" checked={kind === 'cron'} onChange={() => setKind('cron')} />
|
|
198
|
-
cron (5-field)
|
|
199
|
-
</label>
|
|
200
|
-
</div>
|
|
201
|
-
{kind === 'interval' ? (
|
|
202
|
-
<label>
|
|
203
|
-
interval (seconds)
|
|
204
|
-
<input
|
|
205
|
-
type="number"
|
|
206
|
-
min={1}
|
|
207
|
-
value={intervalSec}
|
|
208
|
-
onChange={(e) => setIntervalSec(Number(e.target.value))}
|
|
209
|
-
/>
|
|
210
|
-
</label>
|
|
211
|
-
) : (
|
|
212
|
-
<label>
|
|
213
|
-
cron expression (minute hour dom month dow)
|
|
214
|
-
<input
|
|
215
|
-
type="text"
|
|
216
|
-
placeholder="*/15 * * * *"
|
|
217
|
-
value={cronExpr}
|
|
218
|
-
onChange={(e) => setCronExpr(e.target.value)}
|
|
219
|
-
/>
|
|
220
|
-
</label>
|
|
221
|
-
)}
|
|
222
|
-
<label>
|
|
223
|
-
message
|
|
224
|
-
<textarea
|
|
225
|
-
placeholder="e.g. check your inbox and act on anything new"
|
|
226
|
-
value={message}
|
|
227
|
-
onChange={(e) => setMessage(e.target.value)}
|
|
228
|
-
className="font-mono text-[0.9em] min-h-[80px]"
|
|
229
|
-
/>
|
|
230
|
-
</label>
|
|
231
|
-
<div className="mt-3 flex items-center gap-3">
|
|
232
|
-
<button type="submit" disabled={submitting}>
|
|
233
|
-
{submitting ? 'adding…' : 'add'}
|
|
234
|
-
</button>
|
|
235
|
-
{err && <span className="text-[0.85em] text-[#9B3D3D]">{err}</span>}
|
|
236
|
-
</div>
|
|
237
|
-
</form>
|
|
238
|
-
)
|
|
239
|
-
}
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import type { Agent, Group, Profile } from '@bazilion/api-types'
|
|
2
|
-
import { createFileRoute, useRouter } from '@tanstack/react-router'
|
|
3
|
-
import { createServerFn } from '@tanstack/react-start'
|
|
4
|
-
import { useState } from 'react'
|
|
5
|
-
import { daemonClient } from '../../lib/daemon-client'
|
|
6
|
-
|
|
7
|
-
interface ModelGroup {
|
|
8
|
-
provider: string
|
|
9
|
-
models: string[]
|
|
10
|
-
}
|
|
11
|
-
interface AvailableModelsResponse {
|
|
12
|
-
groups: ModelGroup[]
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface AgentsView {
|
|
16
|
-
agents: Agent[]
|
|
17
|
-
profiles: Profile[]
|
|
18
|
-
groups: Group[]
|
|
19
|
-
modelGroups: ModelGroup[]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const fetchAgents = createServerFn({ method: 'POST' })
|
|
23
|
-
.inputValidator((d: { all: boolean }) => d)
|
|
24
|
-
.handler(async ({ data }): Promise<AgentsView> => {
|
|
25
|
-
const c = daemonClient()
|
|
26
|
-
const [agents, profiles, groups, models] = await Promise.all([
|
|
27
|
-
c.get<Agent[]>(`/api/agents?includeArchived=${data.all}`),
|
|
28
|
-
c.get<Profile[]>('/api/profiles'),
|
|
29
|
-
c.get<Group[]>('/api/groups'),
|
|
30
|
-
c.get<AvailableModelsResponse>('/api/config/available-models'),
|
|
31
|
-
])
|
|
32
|
-
return { agents, profiles, groups, modelGroups: models.groups }
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
export const Route = createFileRoute('/agents/')({
|
|
36
|
-
validateSearch: (s: Record<string, unknown>): { all?: '1' } => ({
|
|
37
|
-
all: s.all === '1' ? '1' : undefined,
|
|
38
|
-
}),
|
|
39
|
-
loaderDeps: ({ search }) => ({ all: search.all === '1' }),
|
|
40
|
-
loader: ({ deps }) => fetchAgents({ data: { all: deps.all } }),
|
|
41
|
-
component: AgentsPage,
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
function AgentsPage() {
|
|
45
|
-
const { agents, profiles, groups, modelGroups } = Route.useLoaderData()
|
|
46
|
-
const { all } = Route.useSearch()
|
|
47
|
-
const showAll = all === '1'
|
|
48
|
-
const router = useRouter()
|
|
49
|
-
|
|
50
|
-
async function archive(id: string) {
|
|
51
|
-
if (!confirm('archive this agent? (reversible)')) return
|
|
52
|
-
await fetch(`/api/agents/${id}/archive`, { method: 'POST' })
|
|
53
|
-
await router.invalidate()
|
|
54
|
-
}
|
|
55
|
-
async function unarchive(id: string) {
|
|
56
|
-
await fetch(`/api/agents/${id}/unarchive`, { method: 'POST' })
|
|
57
|
-
await router.invalidate()
|
|
58
|
-
}
|
|
59
|
-
async function del(id: string) {
|
|
60
|
-
if (!confirm('permanently delete this agent and all its data?')) return
|
|
61
|
-
await fetch(`/api/agents/${id}`, { method: 'DELETE' })
|
|
62
|
-
await router.invalidate()
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<div>
|
|
67
|
-
<h1>agents</h1>
|
|
68
|
-
|
|
69
|
-
<SpawnForm
|
|
70
|
-
profiles={profiles}
|
|
71
|
-
groups={groups}
|
|
72
|
-
modelGroups={modelGroups}
|
|
73
|
-
onSpawned={router.invalidate}
|
|
74
|
-
/>
|
|
75
|
-
|
|
76
|
-
<p>
|
|
77
|
-
<a href={showAll ? '/agents' : '/agents?all=1'}>
|
|
78
|
-
{showAll ? 'hide archived' : 'show archived'}
|
|
79
|
-
</a>
|
|
80
|
-
</p>
|
|
81
|
-
|
|
82
|
-
<table>
|
|
83
|
-
<thead>
|
|
84
|
-
<tr>
|
|
85
|
-
<th>id</th>
|
|
86
|
-
<th>name</th>
|
|
87
|
-
<th>profile</th>
|
|
88
|
-
<th>status</th>
|
|
89
|
-
<th />
|
|
90
|
-
</tr>
|
|
91
|
-
</thead>
|
|
92
|
-
<tbody>
|
|
93
|
-
{agents.length === 0 && (
|
|
94
|
-
<tr>
|
|
95
|
-
<td colSpan={5} className="muted">
|
|
96
|
-
no agents yet
|
|
97
|
-
</td>
|
|
98
|
-
</tr>
|
|
99
|
-
)}
|
|
100
|
-
{agents.map((a) => (
|
|
101
|
-
<tr key={a.id}>
|
|
102
|
-
<td>
|
|
103
|
-
<a href={`/agents/${a.id}`} title={a.id}>
|
|
104
|
-
<code>{a.id.slice(0, 8)}…</code>
|
|
105
|
-
</a>
|
|
106
|
-
</td>
|
|
107
|
-
<td>{a.name}</td>
|
|
108
|
-
<td>
|
|
109
|
-
<code>{a.profileId}</code>
|
|
110
|
-
</td>
|
|
111
|
-
<td>{a.status}</td>
|
|
112
|
-
<td>
|
|
113
|
-
<div className="flex gap-1.5">
|
|
114
|
-
{a.status !== 'archived' ? (
|
|
115
|
-
<button type="button" className="ghost-btn" onClick={() => archive(a.id)}>
|
|
116
|
-
archive
|
|
117
|
-
</button>
|
|
118
|
-
) : (
|
|
119
|
-
<button type="button" className="ghost-btn" onClick={() => unarchive(a.id)}>
|
|
120
|
-
unarchive
|
|
121
|
-
</button>
|
|
122
|
-
)}
|
|
123
|
-
<button
|
|
124
|
-
type="button"
|
|
125
|
-
className="ghost-btn"
|
|
126
|
-
style={{ color: 'var(--color-rose-baziu)' }}
|
|
127
|
-
onClick={() => del(a.id)}
|
|
128
|
-
>
|
|
129
|
-
delete
|
|
130
|
-
</button>
|
|
131
|
-
</div>
|
|
132
|
-
</td>
|
|
133
|
-
</tr>
|
|
134
|
-
))}
|
|
135
|
-
</tbody>
|
|
136
|
-
</table>
|
|
137
|
-
</div>
|
|
138
|
-
)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function SpawnForm({
|
|
142
|
-
profiles,
|
|
143
|
-
groups,
|
|
144
|
-
modelGroups,
|
|
145
|
-
onSpawned,
|
|
146
|
-
}: {
|
|
147
|
-
profiles: Profile[]
|
|
148
|
-
groups: Group[]
|
|
149
|
-
modelGroups: ModelGroup[]
|
|
150
|
-
onSpawned: () => void
|
|
151
|
-
}) {
|
|
152
|
-
const [profileId, setProfileId] = useState('')
|
|
153
|
-
const [name, setName] = useState('')
|
|
154
|
-
const [model, setModel] = useState('')
|
|
155
|
-
// Default to the seeded 'default' group when present so the form matches the
|
|
156
|
-
// server-side fallback. Empty string means "let the daemon pick" — same end
|
|
157
|
-
// result as picking 'default' explicitly.
|
|
158
|
-
const [groupId, setGroupId] = useState(groups.find((g) => g.id === 'default')?.id ?? '')
|
|
159
|
-
const [submitting, setSubmitting] = useState(false)
|
|
160
|
-
const [err, setErr] = useState<string | null>(null)
|
|
161
|
-
|
|
162
|
-
async function submit(e: React.FormEvent<HTMLFormElement>) {
|
|
163
|
-
e.preventDefault()
|
|
164
|
-
if (!profileId) {
|
|
165
|
-
setErr('profile is required')
|
|
166
|
-
return
|
|
167
|
-
}
|
|
168
|
-
setSubmitting(true)
|
|
169
|
-
setErr(null)
|
|
170
|
-
try {
|
|
171
|
-
const body: Record<string, unknown> = { profile: profileId }
|
|
172
|
-
if (name) body.name = name
|
|
173
|
-
if (model) body.model = model
|
|
174
|
-
if (groupId) body.groupId = groupId
|
|
175
|
-
const res = await fetch('/api/agents', {
|
|
176
|
-
method: 'POST',
|
|
177
|
-
headers: { 'content-type': 'application/json' },
|
|
178
|
-
body: JSON.stringify(body),
|
|
179
|
-
})
|
|
180
|
-
if (!res.ok) {
|
|
181
|
-
const b = (await res.json().catch(() => null)) as { error?: string } | null
|
|
182
|
-
throw new Error(b?.error ?? res.statusText)
|
|
183
|
-
}
|
|
184
|
-
// Reset on success.
|
|
185
|
-
setName('')
|
|
186
|
-
setModel('')
|
|
187
|
-
onSpawned()
|
|
188
|
-
} catch (e2) {
|
|
189
|
-
setErr((e2 as Error).message)
|
|
190
|
-
} finally {
|
|
191
|
-
setSubmitting(false)
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return (
|
|
196
|
-
<form className="card" onSubmit={submit}>
|
|
197
|
-
<h3>spawn agent</h3>
|
|
198
|
-
{err && <div className="err">{err}</div>}
|
|
199
|
-
<p className="muted my-2 text-[0.85em]">
|
|
200
|
-
Skills come from the profile's defaults at spawn time. Tweak per-agent skills after the
|
|
201
|
-
fact from the agent detail page.
|
|
202
|
-
</p>
|
|
203
|
-
<div className="flex gap-4">
|
|
204
|
-
<label className="flex-1">
|
|
205
|
-
profile
|
|
206
|
-
<select value={profileId} onChange={(e) => setProfileId(e.target.value)} required>
|
|
207
|
-
<option value="">--</option>
|
|
208
|
-
{profiles.map((p) => (
|
|
209
|
-
<option key={p.id} value={p.id}>
|
|
210
|
-
{p.id}
|
|
211
|
-
</option>
|
|
212
|
-
))}
|
|
213
|
-
</select>
|
|
214
|
-
</label>
|
|
215
|
-
<label className="flex-1">
|
|
216
|
-
name
|
|
217
|
-
<input value={name} onChange={(e) => setName(e.target.value)} />
|
|
218
|
-
</label>
|
|
219
|
-
</div>
|
|
220
|
-
<label>
|
|
221
|
-
model override
|
|
222
|
-
{modelGroups.length === 0 ? (
|
|
223
|
-
<input
|
|
224
|
-
value=""
|
|
225
|
-
disabled
|
|
226
|
-
placeholder="(uses profile default — enable models on /config)"
|
|
227
|
-
/>
|
|
228
|
-
) : (
|
|
229
|
-
<select value={model} onChange={(e) => setModel(e.target.value)}>
|
|
230
|
-
<option value="">(uses profile default)</option>
|
|
231
|
-
{modelGroups.map((g) => (
|
|
232
|
-
<optgroup key={g.provider} label={g.provider}>
|
|
233
|
-
{g.models.map((m) => (
|
|
234
|
-
<option key={m} value={`${g.provider}:${m}`}>
|
|
235
|
-
{`${g.provider}:${m}`}
|
|
236
|
-
</option>
|
|
237
|
-
))}
|
|
238
|
-
</optgroup>
|
|
239
|
-
))}
|
|
240
|
-
</select>
|
|
241
|
-
)}
|
|
242
|
-
</label>
|
|
243
|
-
<label>
|
|
244
|
-
group
|
|
245
|
-
{groups.length === 0 ? (
|
|
246
|
-
<select disabled>
|
|
247
|
-
<option>(no groups — register one on /groups)</option>
|
|
248
|
-
</select>
|
|
249
|
-
) : (
|
|
250
|
-
<select value={groupId} onChange={(e) => setGroupId(e.target.value)}>
|
|
251
|
-
{groups.map((g) => (
|
|
252
|
-
<option key={g.id} value={g.id}>
|
|
253
|
-
{g.id} ({g.name})
|
|
254
|
-
</option>
|
|
255
|
-
))}
|
|
256
|
-
</select>
|
|
257
|
-
)}
|
|
258
|
-
</label>
|
|
259
|
-
|
|
260
|
-
<button type="submit" disabled={submitting}>
|
|
261
|
-
{submitting ? 'spawning…' : 'spawn'}
|
|
262
|
-
</button>
|
|
263
|
-
</form>
|
|
264
|
-
)
|
|
265
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// Catch-all reverse proxy: forwards every browser /api/* request to the
|
|
2
|
-
// daemon. Browser scripts use relative URLs (/api/agents, /api/groups, …)
|
|
3
|
-
// so the bz_token cookie auto-attaches; this proxy translates that cookie
|
|
4
|
-
// into a Bearer header for the daemon, which lives on a different origin.
|
|
5
|
-
//
|
|
6
|
-
// Streams responses (chat NDJSON) and request bodies through unchanged.
|
|
7
|
-
|
|
8
|
-
import { createFileRoute } from '@tanstack/react-router'
|
|
9
|
-
import { getCookie } from '@tanstack/react-start/server'
|
|
10
|
-
import { DAEMON_BASE_URL } from '../../lib/daemon-client'
|
|
11
|
-
|
|
12
|
-
// Hop-by-hop headers per RFC 7230 §6.1, plus host (we're rewriting it) and
|
|
13
|
-
// cookie (we translate cookie → bearer ourselves).
|
|
14
|
-
const STRIP_REQUEST_HEADERS = new Set([
|
|
15
|
-
'host',
|
|
16
|
-
'connection',
|
|
17
|
-
'keep-alive',
|
|
18
|
-
'proxy-authenticate',
|
|
19
|
-
'proxy-authorization',
|
|
20
|
-
'te',
|
|
21
|
-
'trailer',
|
|
22
|
-
'transfer-encoding',
|
|
23
|
-
'upgrade',
|
|
24
|
-
'cookie',
|
|
25
|
-
])
|
|
26
|
-
|
|
27
|
-
const STRIP_RESPONSE_HEADERS = new Set([
|
|
28
|
-
'connection',
|
|
29
|
-
'keep-alive',
|
|
30
|
-
'proxy-authenticate',
|
|
31
|
-
'proxy-authorization',
|
|
32
|
-
'te',
|
|
33
|
-
'trailer',
|
|
34
|
-
'transfer-encoding',
|
|
35
|
-
'upgrade',
|
|
36
|
-
])
|
|
37
|
-
|
|
38
|
-
async function proxy(request: Request): Promise<Response> {
|
|
39
|
-
const incoming = new URL(request.url)
|
|
40
|
-
const target = `${DAEMON_BASE_URL}${incoming.pathname}${incoming.search}`
|
|
41
|
-
|
|
42
|
-
const headers = new Headers()
|
|
43
|
-
for (const [k, v] of request.headers) {
|
|
44
|
-
if (!STRIP_REQUEST_HEADERS.has(k.toLowerCase())) headers.set(k, v)
|
|
45
|
-
}
|
|
46
|
-
// Browser sent the bz_token cookie; translate to Bearer for the daemon.
|
|
47
|
-
// If the request already has an Authorization header (CLI/mobile via the
|
|
48
|
-
// web origin — unusual but possible) leave it alone.
|
|
49
|
-
if (!headers.has('authorization')) {
|
|
50
|
-
const token = getCookie('bz_token')
|
|
51
|
-
if (token) headers.set('authorization', `Bearer ${token}`)
|
|
52
|
-
}
|
|
53
|
-
// Stamp Origin so we stay symmetric with @bazilion/client and any future
|
|
54
|
-
// origin checks the daemon adds keep working.
|
|
55
|
-
headers.set('origin', DAEMON_BASE_URL)
|
|
56
|
-
|
|
57
|
-
const init: RequestInit = { method: request.method, headers, redirect: 'manual' }
|
|
58
|
-
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
59
|
-
init.body = request.body
|
|
60
|
-
// @ts-expect-error — undici needs duplex:'half' for streaming bodies
|
|
61
|
-
init.duplex = 'half'
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const upstream = await fetch(target, init)
|
|
65
|
-
|
|
66
|
-
const respHeaders = new Headers()
|
|
67
|
-
for (const [k, v] of upstream.headers) {
|
|
68
|
-
if (!STRIP_RESPONSE_HEADERS.has(k.toLowerCase())) respHeaders.set(k, v)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return new Response(upstream.body, {
|
|
72
|
-
status: upstream.status,
|
|
73
|
-
statusText: upstream.statusText,
|
|
74
|
-
headers: respHeaders,
|
|
75
|
-
})
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export const Route = createFileRoute('/api/$')({
|
|
79
|
-
server: {
|
|
80
|
-
handlers: {
|
|
81
|
-
GET: ({ request }) => proxy(request),
|
|
82
|
-
POST: ({ request }) => proxy(request),
|
|
83
|
-
PUT: ({ request }) => proxy(request),
|
|
84
|
-
PATCH: ({ request }) => proxy(request),
|
|
85
|
-
DELETE: ({ request }) => proxy(request),
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
})
|