@flame0510/project-aether 1.1.15 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/app/agents/ModelSection.tsx +313 -0
- package/app/agents/PageClient.tsx +83 -4
- package/app/agents/create/page.tsx +8 -21
- package/app/api/agents/[id]/model/route.ts +113 -0
- package/app/api/agents/[id]/recreate/route.ts +10 -34
- package/app/api/agents/[id]/route.ts +10 -29
- package/app/api/agents/create/route.ts +59 -57
- package/app/api/agents/models-summary/route.ts +163 -0
- package/app/api/assistant/route.ts +36 -15
- package/app/api/credentials/[id]/sync/route.ts +3 -3
- package/app/api/credentials/detect/route.ts +126 -176
- package/app/api/credentials/route.ts +3 -0
- package/app/api/gateway/agent/route.ts +23 -6
- package/app/api/gateway/provider/keys.ts +13 -1
- package/app/api/gateway/provider/route.ts +43 -12
- package/app/api/gateway/sync.ts +248 -72
- package/app/api/models/route.ts +28 -34
- package/app/api/provider/auth.ts +65 -0
- package/app/api/provider/upstream.ts +9 -2
- package/app/api/provider/v1/chat/completions/route.ts +22 -16
- package/app/api/provider/v1/models/route.ts +26 -133
- package/app/components/PulseChat.tsx +25 -39
- package/app/components/Skeleton.tsx +132 -0
- package/app/components/ui/RemoveButton.tsx +46 -0
- package/app/components/ui/Select.tsx +3 -2
- package/app/components/ui/index.ts +1 -0
- package/app/credentials/PageClient.tsx +461 -140
- package/app/credentials/loading.tsx +19 -5
- package/app/gateway/PageClient.tsx +257 -673
- package/app/globals.css +8 -0
- package/app/lib/models-context.tsx +43 -7
- package/app/wizard/useWizard.ts +6 -1
- package/bin/rev4a.js +73 -9
- package/docs/ARCHITECTURE.md +92 -33
- package/docs/FRONTEND-ARCHITECTURE.md +36 -6
- package/docs/REV4A.md +62 -30
- package/docs/dev/API-REFERENCE.md +490 -227
- package/docs/dev/DATABASE.md +8 -3
- package/docs/dev/GATEWAY.md +236 -92
- package/docs/dev/PROVIDERS.md +44 -44
- package/docs/rag/DATA-FRESHNESS.md +57 -28
- package/docs/rag/GLOSSARY.md +20 -18
- package/docs/rag/REV4A-OVERVIEW.md +28 -32
- package/docs/rag/WHAT-I-CAN-ANSWER.md +10 -12
- package/instrumentation.ts +9 -1
- package/lib/agent-readiness.ts +110 -0
- package/lib/channelManager.ts +64 -22
- package/lib/container-file.ts +27 -0
- package/lib/credentials/delivery.ts +212 -119
- package/lib/credentials/detect.ts +229 -97
- package/lib/credentials/providers.ts +38 -7
- package/lib/credentials/vault.ts +78 -13
- package/lib/docker-exec.ts +50 -14
- package/lib/model-catalogue.ts +140 -27
- package/lib/rev4a-paths.ts +0 -21
- package/model-pricing.json +118 -110
- package/models.config.json +27 -12
- package/package.json +1 -1
- package/app/api/gateway/route.ts +0 -191
package/app/api/gateway/route.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { type NextRequest } from "next/server";
|
|
2
|
-
/**
|
|
3
|
-
* Gateway Status API
|
|
4
|
-
*
|
|
5
|
-
* Reports the per-agent model settings the Gateway page needs to render its
|
|
6
|
-
* agent cards and pre-fill the "edit default model" form. Only containers with
|
|
7
|
-
* an AGENT_ID label are considered — no hardcoded container names.
|
|
8
|
-
*
|
|
9
|
-
* GET /api/gateway
|
|
10
|
-
*
|
|
11
|
-
* This used to shell out to the OpenClaw CLI inside every container, twice:
|
|
12
|
-
* `openclaw models status --json` (~5.7s) and `openclaw models list --json`
|
|
13
|
-
* (~4.4s), serially, with execSync — so ~10s per agent with the event loop
|
|
14
|
-
* frozen throughout, and roughly 70s on a seven-agent host.
|
|
15
|
-
*
|
|
16
|
-
* Both were avoidable. `models list` produced a model catalogue and alias map
|
|
17
|
-
* that no line of the UI ever read: the page takes its model list from
|
|
18
|
-
* /api/gateway/provider, which reads local files. And `models status` returned,
|
|
19
|
-
* for the two fields actually used, exactly what sits in the agent's own
|
|
20
|
-
* openclaw.json — verified field by field against a live agent. So the CLI was
|
|
21
|
-
* being booted for five seconds to read a file that `cat` returns in 260ms.
|
|
22
|
-
*
|
|
23
|
-
* The response shape is unchanged so the page keeps working untouched; the
|
|
24
|
-
* fields that came only from the discarded CLI output are now reported empty
|
|
25
|
-
* rather than computed at great cost and thrown away.
|
|
26
|
-
*/
|
|
27
|
-
import { NextResponse } from 'next/server';
|
|
28
|
-
import { execFile } from 'child_process';
|
|
29
|
-
import { promisify } from 'util';
|
|
30
|
-
import { requireAuthJWT } from '@/lib/rev4a-auth';
|
|
31
|
-
import { dockerExecNoFail, mapWithConcurrency } from '@/lib/docker-exec';
|
|
32
|
-
|
|
33
|
-
const execFileAsync = promisify(execFile);
|
|
34
|
-
|
|
35
|
-
export const dynamic = 'force-dynamic';
|
|
36
|
-
|
|
37
|
-
/** Agents queried at once. Each is a `docker exec … cat`, cheap but still a process. */
|
|
38
|
-
const AGENT_QUERY_CONCURRENCY = 8;
|
|
39
|
-
|
|
40
|
-
const AGENT_CONFIG_PATH = '/root/.openclaw/openclaw.json';
|
|
41
|
-
|
|
42
|
-
interface GatewayProvider {
|
|
43
|
-
provider: string;
|
|
44
|
-
kind: string;
|
|
45
|
-
detail: string;
|
|
46
|
-
profiles: number;
|
|
47
|
-
labels: string[];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
interface GatewayAgentStatus {
|
|
51
|
-
agentId: string;
|
|
52
|
-
containerName: string;
|
|
53
|
-
state: string;
|
|
54
|
-
defaultModel: string;
|
|
55
|
-
fallbacks: string[];
|
|
56
|
-
allowed: string[];
|
|
57
|
-
aliases: Record<string, string>;
|
|
58
|
-
providers: GatewayProvider[];
|
|
59
|
-
error?: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface AgentRef {
|
|
63
|
-
agentId: string;
|
|
64
|
-
containerName: string;
|
|
65
|
-
state: string;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Containers carrying an AGENT_ID label, with the label read straight out of
|
|
70
|
-
* `docker ps` rather than a follow-up `docker inspect` per container.
|
|
71
|
-
*/
|
|
72
|
-
async function getAgents(): Promise<AgentRef[]> {
|
|
73
|
-
try {
|
|
74
|
-
const { stdout } = await execFileAsync('docker', [
|
|
75
|
-
'ps', '--filter', 'label=AGENT_ID',
|
|
76
|
-
'--format', '{{.Label "AGENT_ID"}}\t{{.Names}}\t{{.State}}',
|
|
77
|
-
], { encoding: 'utf-8', timeout: 5000 });
|
|
78
|
-
|
|
79
|
-
return stdout.trim().split('\n')
|
|
80
|
-
.map((line) => {
|
|
81
|
-
const [agentId, containerName, state] = line.split('\t');
|
|
82
|
-
if (!containerName?.trim()) return null;
|
|
83
|
-
return {
|
|
84
|
-
agentId: agentId?.trim() || containerName.trim(),
|
|
85
|
-
containerName: containerName.trim(),
|
|
86
|
-
state: state?.trim() || 'unknown',
|
|
87
|
-
};
|
|
88
|
-
})
|
|
89
|
-
.filter(Boolean) as AgentRef[];
|
|
90
|
-
} catch {
|
|
91
|
-
return [];
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Read an agent's model settings out of its openclaw.json.
|
|
97
|
-
*
|
|
98
|
-
* `agents.defaults.model` is the same value `openclaw models status` reports as
|
|
99
|
-
* `defaultModel`/`fallbacks`. The CLI additionally resolves an `imageModel`
|
|
100
|
-
* default when the config sets none, but the base image defines no such default
|
|
101
|
-
* (verified: `imageModel: null`), and agent creation always writes an explicit
|
|
102
|
-
* model — so there is no case where the file and the CLI would disagree.
|
|
103
|
-
*/
|
|
104
|
-
async function readAgentStatus(agent: AgentRef): Promise<GatewayAgentStatus> {
|
|
105
|
-
const raw = await dockerExecNoFail(
|
|
106
|
-
agent.containerName,
|
|
107
|
-
['cat', AGENT_CONFIG_PATH],
|
|
108
|
-
{ timeoutMs: 8000 },
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
const base: GatewayAgentStatus = {
|
|
112
|
-
agentId: agent.agentId,
|
|
113
|
-
containerName: agent.containerName,
|
|
114
|
-
state: agent.state,
|
|
115
|
-
defaultModel: '',
|
|
116
|
-
fallbacks: [],
|
|
117
|
-
allowed: [],
|
|
118
|
-
aliases: {},
|
|
119
|
-
providers: [],
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
if (!raw) return { ...base, error: 'config unreadable' };
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
const config = JSON.parse(raw) as Record<string, any>;
|
|
126
|
-
const model = config?.agents?.defaults?.model ?? {};
|
|
127
|
-
return {
|
|
128
|
-
...base,
|
|
129
|
-
defaultModel: typeof model.primary === 'string' ? model.primary : '',
|
|
130
|
-
fallbacks: Array.isArray(model.fallbacks) ? model.fallbacks.map(String) : [],
|
|
131
|
-
};
|
|
132
|
-
} catch {
|
|
133
|
-
return { ...base, error: 'config unparseable' };
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export async function GET(request: NextRequest): Promise<NextResponse> {
|
|
138
|
-
const denied = await requireAuthJWT(request);
|
|
139
|
-
if (denied) return denied;
|
|
140
|
-
try {
|
|
141
|
-
const timestamp = Date.now();
|
|
142
|
-
|
|
143
|
-
const refs = await getAgents();
|
|
144
|
-
const agents = await mapWithConcurrency(refs, AGENT_QUERY_CONCURRENCY, readAgentStatus);
|
|
145
|
-
|
|
146
|
-
// First agent is the "primary" for core model settings
|
|
147
|
-
const primaryAgent = agents[0] ?? null;
|
|
148
|
-
|
|
149
|
-
return NextResponse.json({
|
|
150
|
-
timestamp,
|
|
151
|
-
gateway: 'Rev4a Model Gateway',
|
|
152
|
-
status: 'online',
|
|
153
|
-
// The model catalogue lives in /api/gateway/provider, which reads the
|
|
154
|
-
// bundled config plus user overrides. Recomputing it per agent here cost
|
|
155
|
-
// 4.4s each and was never read.
|
|
156
|
-
models: {
|
|
157
|
-
total: 0,
|
|
158
|
-
available: 0,
|
|
159
|
-
byProvider: [],
|
|
160
|
-
list: [],
|
|
161
|
-
},
|
|
162
|
-
agents: {
|
|
163
|
-
total: agents.length,
|
|
164
|
-
list: agents.map((a) => ({
|
|
165
|
-
agentId: a.agentId,
|
|
166
|
-
containerName: a.containerName,
|
|
167
|
-
state: a.state,
|
|
168
|
-
defaultModel: a.defaultModel,
|
|
169
|
-
fallbacks: a.fallbacks,
|
|
170
|
-
aliases: a.aliases,
|
|
171
|
-
providers: a.providers,
|
|
172
|
-
})),
|
|
173
|
-
},
|
|
174
|
-
aliases: {},
|
|
175
|
-
coreModel: primaryAgent
|
|
176
|
-
? {
|
|
177
|
-
defaultModel: primaryAgent.defaultModel,
|
|
178
|
-
fallbacks: primaryAgent.fallbacks,
|
|
179
|
-
}
|
|
180
|
-
: null,
|
|
181
|
-
// Provider credential state comes from /api/gateway/provider (`configured`
|
|
182
|
-
// per provider), which reads provider-keys.json directly.
|
|
183
|
-
apiKeys: {
|
|
184
|
-
configured: [],
|
|
185
|
-
all: [],
|
|
186
|
-
},
|
|
187
|
-
});
|
|
188
|
-
} catch (e: unknown) {
|
|
189
|
-
return NextResponse.json({ error: (e as Error).message }, { status: 500 });
|
|
190
|
-
}
|
|
191
|
-
}
|