nolo-cli 0.1.34 → 0.1.36
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 -1
- package/agent-runtime/index.ts +2 -0
- package/agent-runtime/localToolPolicy.ts +1 -1
- package/agent-runtime/localWorkspaceTools.ts +5 -2
- package/agent-runtime/platformChatProvider.ts +17 -9
- package/agent-runtime/providerResolution.ts +71 -13
- package/agentCommandSupport.ts +4 -0
- package/agentListCommands.ts +73 -11
- package/agentListHelpers.ts +56 -1
- package/agentRecordHelpers.ts +45 -5
- package/cli/agentCommandSupport.ts +4 -0
- package/cli/agentListCommands.ts +73 -11
- package/cli/agentListHelpers.ts +56 -1
- package/cli/agentRecordHelpers.ts +45 -5
- package/cli/cliSpaceHelpers.ts +39 -0
- package/cli/client/localRuntimeAdapter.ts +86 -2
- package/cli/connectorWebSocketTarget.ts +10 -3
- package/cli/dialogCommands.ts +446 -0
- package/cli/dialogInternalCommandEntries.ts +13 -0
- package/cli/globalRecordOperations.ts +258 -0
- package/cli/internalCommandEntries.ts +2 -0
- package/cli/localRuntimeAuthority.ts +182 -0
- package/cli/localRuntimeDb.ts +2 -4
- package/cli/machineWsRunDispatch.ts +42 -3
- package/cli/machineWsSession.ts +2 -0
- package/cli/runtimeDoctorCommands.ts +55 -5
- package/cliSpaceHelpers.ts +39 -0
- package/client/localRuntimeAdapter.ts +86 -2
- package/connectorWebSocketTarget.ts +10 -3
- package/database/server/cliAuthorityBrokerClient.ts +227 -0
- package/database/server/cliAuthorityBrokerServer.ts +283 -0
- package/database/server/cliAuthorityBrokerTypes.ts +43 -0
- package/database/server/cliAuthorityStoreDriver.ts +98 -0
- package/database/server/levelAuthorityStore.ts +46 -26
- package/database/tombstones.ts +52 -0
- package/database/userDataMerge.ts +95 -0
- package/dialogCommands.ts +446 -0
- package/dialogInternalCommandEntries.ts +13 -0
- package/globalRecordOperations.ts +258 -0
- package/internalCommandEntries.ts +2 -0
- package/localRuntimeAuthority.ts +182 -0
- package/localRuntimeDb.ts +2 -4
- package/machineWsRunDispatch.ts +42 -3
- package/machineWsSession.ts +2 -0
- package/package.json +18 -6
- package/runtimeDoctorCommands.ts +55 -5
- package/database/server/db.ts +0 -99
- package/database/server/ensureDbOpen.ts +0 -12
- package/database/server/memoryAuthorityStore.ts +0 -133
- package/database/server/serverStoreFactory.ts +0 -118
package/cli/agentListCommands.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getReadableCliDb, type AgentCommandDeps } from "./agentCommandSupport";
|
|
2
2
|
import {
|
|
3
|
+
decorateAgentsWithPublicStatusAcrossServers,
|
|
3
4
|
listLocalCachedAgents,
|
|
5
|
+
listRemoteAgentsAcrossServers,
|
|
4
6
|
listRemoteAgents,
|
|
5
7
|
parseAgentListArgs,
|
|
6
8
|
type ListedAgent,
|
|
@@ -9,11 +11,15 @@ import {
|
|
|
9
11
|
queryUserRecords,
|
|
10
12
|
readDbRecord,
|
|
11
13
|
} from "./agentRecordHelpers";
|
|
14
|
+
import { buildSpaceLookup, getSpaceContentKeys } from "./cliSpaceHelpers";
|
|
12
15
|
import {
|
|
13
16
|
parseUserIdFromAuthToken,
|
|
17
|
+
readOption,
|
|
14
18
|
resolveAuthToken,
|
|
19
|
+
resolveServerCandidates,
|
|
15
20
|
resolveServerUrl,
|
|
16
21
|
} from "./cliEnvHelpers";
|
|
22
|
+
import { readLiveDbRecordAfterTombstoneMerge } from "./globalRecordOperations";
|
|
17
23
|
|
|
18
24
|
export async function runAgentListCommand(
|
|
19
25
|
args: string[],
|
|
@@ -22,6 +28,7 @@ export async function runAgentListCommand(
|
|
|
22
28
|
const env = deps.env ?? process.env;
|
|
23
29
|
const output = deps.output ?? process.stdout;
|
|
24
30
|
const { wantJson, publicOnly, idsOnly, includeLegacy } = parseAgentListArgs(args);
|
|
31
|
+
const spaceInput = readOption(args, "--space") ?? readOption(args, "--space-id");
|
|
25
32
|
|
|
26
33
|
const authToken = resolveAuthToken(args, env);
|
|
27
34
|
if (!authToken) {
|
|
@@ -35,34 +42,79 @@ export async function runAgentListCommand(
|
|
|
35
42
|
return 1;
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
const db = deps.db ?? await getReadableCliDb(output);
|
|
39
45
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
40
46
|
const fallbackFetchImpl = deps.fallbackFetchImpl;
|
|
47
|
+
const serverUrl = resolveServerUrl(args, env);
|
|
48
|
+
const serverUrls = resolveServerCandidates(args, env, serverUrl);
|
|
41
49
|
|
|
42
50
|
try {
|
|
43
51
|
let agents: ListedAgent[];
|
|
44
|
-
let source: "local-cache" | "remote-cache";
|
|
52
|
+
let source: "local-cache" | "remote-cache" | "global-cache";
|
|
53
|
+
let serverFailures: Array<{ serverUrl: string; error: string }> = [];
|
|
45
54
|
try {
|
|
46
|
-
|
|
47
|
-
source = "local-cache";
|
|
48
|
-
} catch {
|
|
49
|
-
const serverUrl = resolveServerUrl(args, env);
|
|
50
|
-
agents = await listRemoteAgents({
|
|
55
|
+
const remoteResult = await listRemoteAgentsAcrossServers({
|
|
51
56
|
authToken,
|
|
52
57
|
fallbackFetchImpl,
|
|
53
58
|
fetchImpl,
|
|
54
59
|
includeLegacy,
|
|
55
|
-
|
|
60
|
+
serverUrls,
|
|
56
61
|
userId,
|
|
57
|
-
queryUserRecords,
|
|
58
|
-
readDbRecord,
|
|
59
62
|
});
|
|
60
|
-
|
|
63
|
+
agents = remoteResult.agents;
|
|
64
|
+
serverFailures = remoteResult.failures;
|
|
65
|
+
source = "global-cache";
|
|
66
|
+
} catch {
|
|
67
|
+
try {
|
|
68
|
+
const db = deps.db ?? await getReadableCliDb(output);
|
|
69
|
+
agents = await listLocalCachedAgents({ db, userId });
|
|
70
|
+
source = "local-cache";
|
|
71
|
+
} catch {
|
|
72
|
+
agents = await listRemoteAgents({
|
|
73
|
+
authToken,
|
|
74
|
+
fallbackFetchImpl,
|
|
75
|
+
fetchImpl,
|
|
76
|
+
includeLegacy,
|
|
77
|
+
serverUrl,
|
|
78
|
+
userId,
|
|
79
|
+
queryUserRecords,
|
|
80
|
+
readDbRecord,
|
|
81
|
+
});
|
|
82
|
+
source = "remote-cache";
|
|
83
|
+
}
|
|
61
84
|
}
|
|
62
85
|
|
|
63
86
|
if (!includeLegacy) {
|
|
64
87
|
agents = agents.filter((agent) => !agent.privateKey.startsWith("cybot-"));
|
|
65
88
|
}
|
|
89
|
+
let resolvedSpaceId: string | null = null;
|
|
90
|
+
if (spaceInput) {
|
|
91
|
+
const { spaceId, spaceKey } = buildSpaceLookup(spaceInput);
|
|
92
|
+
resolvedSpaceId = spaceId;
|
|
93
|
+
const spaceRead = await readLiveDbRecordAfterTombstoneMerge({
|
|
94
|
+
authToken,
|
|
95
|
+
dbKey: spaceKey,
|
|
96
|
+
fallbackFetchImpl,
|
|
97
|
+
fetchImpl,
|
|
98
|
+
serverUrls,
|
|
99
|
+
});
|
|
100
|
+
serverFailures = [...serverFailures, ...spaceRead.failures];
|
|
101
|
+
const spaceRecord = spaceRead.record;
|
|
102
|
+
const spaceContentKeys = getSpaceContentKeys(spaceRecord);
|
|
103
|
+
agents = agents.filter((agent) =>
|
|
104
|
+
spaceContentKeys.has(agent.privateKey) ||
|
|
105
|
+
spaceContentKeys.has(agent.publicKey) ||
|
|
106
|
+
spaceContentKeys.has(agent.id)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
if (source === "global-cache") {
|
|
110
|
+
await decorateAgentsWithPublicStatusAcrossServers({
|
|
111
|
+
agents,
|
|
112
|
+
authToken,
|
|
113
|
+
fallbackFetchImpl,
|
|
114
|
+
fetchImpl,
|
|
115
|
+
serverUrls,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
66
118
|
if (publicOnly) {
|
|
67
119
|
agents = agents.filter((agent) => agent.publicRecordExists);
|
|
68
120
|
}
|
|
@@ -75,6 +127,9 @@ export async function runAgentListCommand(
|
|
|
75
127
|
if (wantJson) {
|
|
76
128
|
output.write(JSON.stringify({
|
|
77
129
|
userId,
|
|
130
|
+
...(resolvedSpaceId ? { spaceId: resolvedSpaceId } : {}),
|
|
131
|
+
targetServers: serverUrls,
|
|
132
|
+
...(serverFailures.length ? { serverFailures } : {}),
|
|
78
133
|
total: agents.length,
|
|
79
134
|
publicCount: agents.filter((agent) => agent.publicRecordExists).length,
|
|
80
135
|
source,
|
|
@@ -85,6 +140,13 @@ export async function runAgentListCommand(
|
|
|
85
140
|
}
|
|
86
141
|
|
|
87
142
|
output.write(`userId: ${userId}\n`);
|
|
143
|
+
if (resolvedSpaceId) {
|
|
144
|
+
output.write(`spaceId: ${resolvedSpaceId}\n`);
|
|
145
|
+
}
|
|
146
|
+
output.write(`targetServers: ${serverUrls.join(", ")}\n`);
|
|
147
|
+
if (serverFailures.length) {
|
|
148
|
+
output.write(`serverFailures: ${serverFailures.length}\n`);
|
|
149
|
+
}
|
|
88
150
|
output.write(`total agents: ${agents.length}\n`);
|
|
89
151
|
output.write(`public agents: ${agents.filter((agent) => agent.publicRecordExists).length}\n`);
|
|
90
152
|
output.write(`source: ${source}\n`);
|
package/cli/agentListHelpers.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { CliKvDb } from "./client/hybridRecordStore";
|
|
2
|
+
import {
|
|
3
|
+
listUserRecordsFromServers,
|
|
4
|
+
readLiveDbRecordAfterTombstoneMerge,
|
|
5
|
+
} from "./globalRecordOperations";
|
|
2
6
|
|
|
3
7
|
export type ListedAgent = {
|
|
4
8
|
id: string;
|
|
@@ -93,7 +97,7 @@ export async function listLocalCachedAgents(args: {
|
|
|
93
97
|
}) {
|
|
94
98
|
const privateRecords = new Map<string, any>();
|
|
95
99
|
const publicKeys = new Set<string>();
|
|
96
|
-
for await (const [key, value] of args.db.iterator()) {
|
|
100
|
+
for await (const [key, value] of args.db.iterator({ gte: "", lte: "\uffff" })) {
|
|
97
101
|
if (typeof key !== "string" || !value || typeof value !== "object") continue;
|
|
98
102
|
if (key.startsWith(`agent-${args.userId}-`) || key.startsWith(`cybot-${args.userId}-`)) {
|
|
99
103
|
privateRecords.set(key, { ...(value as Record<string, unknown>), dbKey: key });
|
|
@@ -185,3 +189,54 @@ export async function listRemoteAgents(args: {
|
|
|
185
189
|
);
|
|
186
190
|
return agents;
|
|
187
191
|
}
|
|
192
|
+
|
|
193
|
+
export async function listRemoteAgentsAcrossServers(args: {
|
|
194
|
+
authToken: string;
|
|
195
|
+
fallbackFetchImpl?: typeof fetch;
|
|
196
|
+
fetchImpl: typeof fetch;
|
|
197
|
+
includeLegacy: boolean;
|
|
198
|
+
serverUrls: string[];
|
|
199
|
+
userId: string;
|
|
200
|
+
}) {
|
|
201
|
+
const remoteResult = await listUserRecordsFromServers({
|
|
202
|
+
authToken: args.authToken,
|
|
203
|
+
fallbackFetchImpl: args.fallbackFetchImpl,
|
|
204
|
+
fetchImpl: args.fetchImpl,
|
|
205
|
+
label: "agent query",
|
|
206
|
+
serverUrls: args.serverUrls,
|
|
207
|
+
type: args.includeLegacy ? ["agent", "cybot"] : "agent",
|
|
208
|
+
userId: args.userId,
|
|
209
|
+
});
|
|
210
|
+
const agents = sortListedAgents(
|
|
211
|
+
remoteResult.records
|
|
212
|
+
.map((record) => normalizeListedAgent(record))
|
|
213
|
+
.filter((agent): agent is ListedAgent => agent != null)
|
|
214
|
+
);
|
|
215
|
+
return { agents, failures: remoteResult.failures };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export async function decorateAgentsWithPublicStatusAcrossServers(args: {
|
|
219
|
+
agents: ListedAgent[];
|
|
220
|
+
authToken: string;
|
|
221
|
+
fallbackFetchImpl?: typeof fetch;
|
|
222
|
+
fetchImpl: typeof fetch;
|
|
223
|
+
serverUrls: string[];
|
|
224
|
+
}) {
|
|
225
|
+
await Promise.all(
|
|
226
|
+
args.agents.map(async (agent) => {
|
|
227
|
+
try {
|
|
228
|
+
const result = await readLiveDbRecordAfterTombstoneMerge({
|
|
229
|
+
authToken: args.authToken,
|
|
230
|
+
dbKey: agent.publicKey,
|
|
231
|
+
fallbackFetchImpl: args.fallbackFetchImpl,
|
|
232
|
+
fetchImpl: args.fetchImpl,
|
|
233
|
+
serverUrls: args.serverUrls,
|
|
234
|
+
});
|
|
235
|
+
agent.publicRecordExists = result.record?.isPublic === true;
|
|
236
|
+
} catch {
|
|
237
|
+
agent.publicRecordExists = false;
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
);
|
|
241
|
+
return args.agents;
|
|
242
|
+
}
|
|
@@ -125,10 +125,12 @@ export async function readDbRecord(args: {
|
|
|
125
125
|
authToken: string;
|
|
126
126
|
fallbackFetchImpl?: typeof fetch;
|
|
127
127
|
fetchImpl: typeof fetch;
|
|
128
|
+
includeDeleted?: boolean;
|
|
128
129
|
serverUrl: string;
|
|
129
130
|
}) {
|
|
131
|
+
const query = args.includeDeleted ? "?includeDeleted=true" : "";
|
|
130
132
|
const res = await fetchWithTransportFallback(
|
|
131
|
-
`${args.serverUrl}/api/v1/db/read/${encodeURIComponent(args.dbKey)}`,
|
|
133
|
+
`${args.serverUrl}/api/v1/db/read/${encodeURIComponent(args.dbKey)}${query}`,
|
|
132
134
|
{
|
|
133
135
|
method: "GET",
|
|
134
136
|
headers: { Authorization: `Bearer ${args.authToken}` },
|
|
@@ -146,19 +148,29 @@ export async function queryUserRecords(args: {
|
|
|
146
148
|
authToken: string;
|
|
147
149
|
fallbackFetchImpl?: typeof fetch;
|
|
148
150
|
fetchImpl: typeof fetch;
|
|
151
|
+
limit?: number;
|
|
149
152
|
serverUrl: string;
|
|
153
|
+
summary?: boolean;
|
|
154
|
+
includeDeleted?: boolean;
|
|
150
155
|
userId: string;
|
|
151
|
-
type:
|
|
152
|
-
}) {
|
|
156
|
+
type: string | string[];
|
|
157
|
+
}): Promise<any[]> {
|
|
158
|
+
const query = typeof args.limit === "number" && args.limit > 0
|
|
159
|
+
? `?limit=${Math.floor(args.limit)}`
|
|
160
|
+
: "";
|
|
153
161
|
const res = await fetchWithTransportFallback(
|
|
154
|
-
`${args.serverUrl}/api/v1/db/query/${encodeURIComponent(args.userId)}`,
|
|
162
|
+
`${args.serverUrl}/api/v1/db/query/${encodeURIComponent(args.userId)}${query}`,
|
|
155
163
|
{
|
|
156
164
|
method: "POST",
|
|
157
165
|
headers: {
|
|
158
166
|
Authorization: `Bearer ${args.authToken}`,
|
|
159
167
|
"Content-Type": "application/json",
|
|
160
168
|
},
|
|
161
|
-
body: JSON.stringify({
|
|
169
|
+
body: JSON.stringify({
|
|
170
|
+
type: args.type,
|
|
171
|
+
...(args.includeDeleted ? { includeDeleted: true } : {}),
|
|
172
|
+
...(args.summary ? { summary: true } : {}),
|
|
173
|
+
}),
|
|
162
174
|
},
|
|
163
175
|
args
|
|
164
176
|
);
|
|
@@ -173,6 +185,34 @@ export async function queryUserRecords(args: {
|
|
|
173
185
|
: [];
|
|
174
186
|
}
|
|
175
187
|
|
|
188
|
+
export async function deleteDbRecord(args: {
|
|
189
|
+
dbKey: string;
|
|
190
|
+
deleteOptions?: { type?: "single" | "table" | "messages" };
|
|
191
|
+
authToken: string;
|
|
192
|
+
fallbackFetchImpl?: typeof fetch;
|
|
193
|
+
fetchImpl: typeof fetch;
|
|
194
|
+
serverUrl: string;
|
|
195
|
+
}) {
|
|
196
|
+
const type = args.deleteOptions?.type;
|
|
197
|
+
const query =
|
|
198
|
+
type && type !== "single"
|
|
199
|
+
? `?type=${encodeURIComponent(type)}`
|
|
200
|
+
: "";
|
|
201
|
+
const res = await fetchWithTransportFallback(
|
|
202
|
+
`${args.serverUrl}/api/v1/db/delete/${encodeURIComponent(args.dbKey)}${query}`,
|
|
203
|
+
{
|
|
204
|
+
method: "DELETE",
|
|
205
|
+
headers: { Authorization: `Bearer ${args.authToken}` },
|
|
206
|
+
},
|
|
207
|
+
args
|
|
208
|
+
);
|
|
209
|
+
const data = await res.json().catch(() => ({}));
|
|
210
|
+
if (!res.ok) {
|
|
211
|
+
throw new Error(`delete failed: HTTP ${res.status} ${JSON.stringify(data)}`);
|
|
212
|
+
}
|
|
213
|
+
return data;
|
|
214
|
+
}
|
|
215
|
+
|
|
176
216
|
export async function writeAgentRecord(args: {
|
|
177
217
|
agentKey: string;
|
|
178
218
|
authToken: string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function normalizeSpaceIdInput(rawInput: string) {
|
|
2
|
+
const raw = rawInput.trim();
|
|
3
|
+
if (!raw) return "";
|
|
4
|
+
|
|
5
|
+
if (raw.startsWith("http://") || raw.startsWith("https://")) {
|
|
6
|
+
const url = new URL(raw);
|
|
7
|
+
const match = url.pathname.match(/^\/space\/([^/?#]+)/);
|
|
8
|
+
if (match?.[1]) return decodeURIComponent(match[1]);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return raw.startsWith("space-") ? raw.slice("space-".length) : raw;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function buildSpaceLookup(rawInput: string) {
|
|
15
|
+
const spaceId = normalizeSpaceIdInput(rawInput);
|
|
16
|
+
return {
|
|
17
|
+
spaceId,
|
|
18
|
+
spaceKey: spaceId.startsWith("space-") ? spaceId : `space-${spaceId}`,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getSpaceContentKeys(spaceRecord: any): Set<string> {
|
|
23
|
+
const keys = new Set<string>();
|
|
24
|
+
const contents = spaceRecord?.contents;
|
|
25
|
+
if (!contents || typeof contents !== "object") return keys;
|
|
26
|
+
|
|
27
|
+
for (const [entryKey, value] of Object.entries(contents)) {
|
|
28
|
+
if (typeof entryKey === "string" && entryKey.trim()) {
|
|
29
|
+
keys.add(entryKey.trim());
|
|
30
|
+
}
|
|
31
|
+
if (value && typeof value === "object") {
|
|
32
|
+
const contentKey = (value as any).contentKey;
|
|
33
|
+
if (typeof contentKey === "string" && contentKey.trim()) {
|
|
34
|
+
keys.add(contentKey.trim());
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return keys;
|
|
39
|
+
}
|
|
@@ -221,6 +221,29 @@ function buildRequestTimeoutSignal(timeoutMs?: number) {
|
|
|
221
221
|
return controller.signal;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
function summarizeEndpoint(value: unknown) {
|
|
225
|
+
if (typeof value !== "string" || !value.trim()) return undefined;
|
|
226
|
+
try {
|
|
227
|
+
const url = new URL(value);
|
|
228
|
+
return `${url.protocol}//${url.host}${url.pathname}`;
|
|
229
|
+
} catch {
|
|
230
|
+
return "invalid-url";
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function parseJsonObject(raw: string) {
|
|
235
|
+
try {
|
|
236
|
+
const parsed = JSON.parse(raw);
|
|
237
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
238
|
+
} catch {
|
|
239
|
+
return {};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function logLocalRuntimeDiagnostic(event: string, fields: Record<string, unknown>) {
|
|
244
|
+
console.error(`[nolo-local-runtime] ${event} ${JSON.stringify(fields)}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
224
247
|
function buildOpenAiTools(args: { toolNames?: string[]; env: EnvLike }) {
|
|
225
248
|
const toolset = buildLocalWorkspaceToolsetForEnv(args);
|
|
226
249
|
return [
|
|
@@ -476,6 +499,20 @@ export function createCliLocalRuntimeAdapter(
|
|
|
476
499
|
agentConfig,
|
|
477
500
|
env: deps.env,
|
|
478
501
|
});
|
|
502
|
+
logLocalRuntimeDiagnostic("provider.selected", {
|
|
503
|
+
agentKey: agentConfig.key,
|
|
504
|
+
transport: "platform-proxy",
|
|
505
|
+
apiSource: agentConfig.apiSource ?? null,
|
|
506
|
+
provider: providerConfig.provider,
|
|
507
|
+
model: providerConfig.model,
|
|
508
|
+
endpoint: summarizeEndpoint(providerConfig.endpoint) ?? null,
|
|
509
|
+
proxyServer: summarizeEndpoint(providerConfig.serverUrl) ?? null,
|
|
510
|
+
hasAuthToken: Boolean(providerConfig.authToken),
|
|
511
|
+
hasApiKey: Boolean(providerConfig.apiKey),
|
|
512
|
+
apiKeyHeader: providerConfig.apiKeyHeader ?? null,
|
|
513
|
+
useServerProxy: agentConfig.useServerProxy ?? null,
|
|
514
|
+
customProviderEndpoint: summarizeEndpoint(agentConfig.customProviderUrl) ?? null,
|
|
515
|
+
});
|
|
479
516
|
return {
|
|
480
517
|
model: providerConfig.model,
|
|
481
518
|
complete: async (messages, options) => {
|
|
@@ -492,6 +529,16 @@ export function createCliLocalRuntimeAdapter(
|
|
|
492
529
|
tools,
|
|
493
530
|
});
|
|
494
531
|
const signal = buildRequestTimeoutSignal(options?.timeoutMs);
|
|
532
|
+
logLocalRuntimeDiagnostic("provider.request.start", {
|
|
533
|
+
agentKey: agentConfig.key,
|
|
534
|
+
transport: "platform-proxy",
|
|
535
|
+
requestUrl: summarizeEndpoint(request.url) ?? null,
|
|
536
|
+
endpoint: summarizeEndpoint(providerConfig.endpoint) ?? null,
|
|
537
|
+
model: providerConfig.model,
|
|
538
|
+
messageCount: messages.length,
|
|
539
|
+
toolCount: tools.length,
|
|
540
|
+
timeoutMs: options?.timeoutMs ?? null,
|
|
541
|
+
});
|
|
495
542
|
const res = await fetchWithTransientRetry(fetchImpl, request.url, {
|
|
496
543
|
...request.init,
|
|
497
544
|
...(signal ? { signal } : {}),
|
|
@@ -499,7 +546,15 @@ export function createCliLocalRuntimeAdapter(
|
|
|
499
546
|
sleep: deps.sleep,
|
|
500
547
|
loopbackRequest,
|
|
501
548
|
});
|
|
502
|
-
const
|
|
549
|
+
const raw = await res.text().catch(() => "");
|
|
550
|
+
logLocalRuntimeDiagnostic("provider.request.result", {
|
|
551
|
+
agentKey: agentConfig.key,
|
|
552
|
+
transport: "platform-proxy",
|
|
553
|
+
status: res.status,
|
|
554
|
+
ok: res.ok,
|
|
555
|
+
responseBytes: raw.length,
|
|
556
|
+
});
|
|
557
|
+
const data = parsePlatformChatCompletionData(raw);
|
|
503
558
|
if (!res.ok) {
|
|
504
559
|
throw new Error(`platform provider failed: HTTP ${res.status} ${JSON.stringify(data)}`);
|
|
505
560
|
}
|
|
@@ -516,6 +571,18 @@ export function createCliLocalRuntimeAdapter(
|
|
|
516
571
|
agentConfig,
|
|
517
572
|
env: deps.env,
|
|
518
573
|
});
|
|
574
|
+
logLocalRuntimeDiagnostic("provider.selected", {
|
|
575
|
+
agentKey: agentConfig.key,
|
|
576
|
+
transport: "direct-openai-compatible",
|
|
577
|
+
apiSource: agentConfig.apiSource ?? null,
|
|
578
|
+
provider: providerConfig.provider,
|
|
579
|
+
model: providerConfig.model,
|
|
580
|
+
endpoint: summarizeEndpoint(providerConfig.endpoint) ?? null,
|
|
581
|
+
hasApiKey: Boolean(providerConfig.apiKey),
|
|
582
|
+
apiKeyHeader: providerConfig.apiKeyHeader ?? null,
|
|
583
|
+
useServerProxy: agentConfig.useServerProxy ?? null,
|
|
584
|
+
customProviderEndpoint: summarizeEndpoint(agentConfig.customProviderUrl) ?? null,
|
|
585
|
+
});
|
|
519
586
|
return {
|
|
520
587
|
model: providerConfig.model,
|
|
521
588
|
complete: async (messages, options) => {
|
|
@@ -532,6 +599,15 @@ export function createCliLocalRuntimeAdapter(
|
|
|
532
599
|
tools,
|
|
533
600
|
});
|
|
534
601
|
const signal = buildRequestTimeoutSignal(options?.timeoutMs);
|
|
602
|
+
logLocalRuntimeDiagnostic("provider.request.start", {
|
|
603
|
+
agentKey: agentConfig.key,
|
|
604
|
+
transport: "direct-openai-compatible",
|
|
605
|
+
requestUrl: summarizeEndpoint(request.url) ?? null,
|
|
606
|
+
model: providerConfig.model,
|
|
607
|
+
messageCount: messages.length,
|
|
608
|
+
toolCount: tools.length,
|
|
609
|
+
timeoutMs: options?.timeoutMs ?? null,
|
|
610
|
+
});
|
|
535
611
|
const res = await fetchWithTransientRetry(fetchImpl, request.url, {
|
|
536
612
|
...request.init,
|
|
537
613
|
...(signal ? { signal } : {}),
|
|
@@ -539,7 +615,15 @@ export function createCliLocalRuntimeAdapter(
|
|
|
539
615
|
sleep: deps.sleep,
|
|
540
616
|
loopbackRequest,
|
|
541
617
|
});
|
|
542
|
-
const
|
|
618
|
+
const raw = await res.text().catch(() => "");
|
|
619
|
+
logLocalRuntimeDiagnostic("provider.request.result", {
|
|
620
|
+
agentKey: agentConfig.key,
|
|
621
|
+
transport: "direct-openai-compatible",
|
|
622
|
+
status: res.status,
|
|
623
|
+
ok: res.ok,
|
|
624
|
+
responseBytes: raw.length,
|
|
625
|
+
});
|
|
626
|
+
const data = parseJsonObject(raw);
|
|
543
627
|
if (!res.ok) {
|
|
544
628
|
throw new Error(`local provider failed: HTTP ${res.status} ${JSON.stringify(data)}`);
|
|
545
629
|
}
|
|
@@ -49,14 +49,21 @@ function parseRetryAfterMs(response: Response, bodyRetryAfterMs?: unknown) {
|
|
|
49
49
|
export async function resolveConnectorWebSocketTarget(input: {
|
|
50
50
|
serverUrl: string;
|
|
51
51
|
machineId: string;
|
|
52
|
+
connectorSurface?: string;
|
|
52
53
|
headers: Record<string, string>;
|
|
53
54
|
fetchImpl?: typeof fetch;
|
|
54
55
|
}) {
|
|
55
56
|
const directWsUrl = new URL(input.serverUrl);
|
|
56
57
|
directWsUrl.protocol = directWsUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
57
|
-
directWsUrl.pathname = "/api/connector/ws";
|
|
58
|
-
directWsUrl.search = "";
|
|
59
|
-
directWsUrl.searchParams.set("machineId", input.machineId);
|
|
58
|
+
directWsUrl.pathname = "/api/connector/ws";
|
|
59
|
+
directWsUrl.search = "";
|
|
60
|
+
directWsUrl.searchParams.set("machineId", input.machineId);
|
|
61
|
+
if (input.connectorSurface?.trim()) {
|
|
62
|
+
directWsUrl.searchParams.set(
|
|
63
|
+
"connectorSurface",
|
|
64
|
+
input.connectorSurface.trim().toLowerCase()
|
|
65
|
+
);
|
|
66
|
+
}
|
|
60
67
|
|
|
61
68
|
const probeUrl = new URL(input.serverUrl);
|
|
62
69
|
probeUrl.pathname = "/api/connector/ws";
|