nolo-cli 0.1.35 → 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/agent-runtime/index.ts +2 -0
- package/agent-runtime/platformChatProvider.ts +17 -9
- package/agent-runtime/providerResolution.ts +71 -11
- package/cli/client/localRuntimeAdapter.ts +86 -2
- package/cli/machineWsRunDispatch.ts +42 -0
- package/client/localRuntimeAdapter.ts +86 -2
- package/machineWsRunDispatch.ts +42 -0
- package/package.json +1 -1
package/agent-runtime/index.ts
CHANGED
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
buildProviderExecutionPlan,
|
|
8
8
|
canUsePlatformChatProvider as canUsePlatformChatProviderFromEnv,
|
|
9
9
|
hasDirectOpenAiCompatibleProvider as hasDirectOpenAiCompatibleProviderFromEnv,
|
|
10
|
+
resolveAgentRuntimeLocation,
|
|
10
11
|
resolvePlatformAuthToken,
|
|
11
12
|
resolvePlatformServerUrl,
|
|
12
|
-
|
|
13
|
+
resolveProviderTransportDecision,
|
|
13
14
|
} from "./providerResolution";
|
|
14
15
|
|
|
15
16
|
type EnvLike = Record<string, string | undefined>;
|
|
@@ -206,16 +207,23 @@ export function hasDirectOpenAiCompatibleProvider(env: EnvLike) {
|
|
|
206
207
|
return hasDirectOpenAiCompatibleProviderFromEnv(env);
|
|
207
208
|
}
|
|
208
209
|
|
|
209
|
-
function agentRequiresPlatformChatProvider(agentConfig?: AgentRuntimeAgentConfig) {
|
|
210
|
-
if (agentConfig?.apiSource === "platform") return true;
|
|
211
|
-
if (agentConfig?.apiSource === "custom" || agentConfig?.customProviderUrl?.trim()) return false;
|
|
212
|
-
return agentConfig?.useServerProxy === true;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
210
|
export function shouldUsePlatformChatProvider(
|
|
216
211
|
env: EnvLike,
|
|
217
212
|
agentConfig?: AgentRuntimeAgentConfig
|
|
218
213
|
) {
|
|
219
|
-
if (
|
|
220
|
-
|
|
214
|
+
if (!agentConfig) {
|
|
215
|
+
return resolveProviderTransportDecision({
|
|
216
|
+
agentConfig: { key: "default-platform" },
|
|
217
|
+
env,
|
|
218
|
+
runtimeLocation: "local-host",
|
|
219
|
+
}).transport === "proxy";
|
|
220
|
+
}
|
|
221
|
+
return resolveProviderTransportDecision({
|
|
222
|
+
agentConfig,
|
|
223
|
+
env,
|
|
224
|
+
runtimeLocation: resolveAgentRuntimeLocation({
|
|
225
|
+
agentConfig,
|
|
226
|
+
runtimeKind: "local",
|
|
227
|
+
}),
|
|
228
|
+
}).transport === "proxy";
|
|
221
229
|
}
|
|
@@ -16,6 +16,21 @@ const PROVIDER_ENDPOINTS: Record<string, string> = {
|
|
|
16
16
|
|
|
17
17
|
export type AgentProviderMode = "cli" | "platform" | "custom";
|
|
18
18
|
export type ProviderExecutionTransport = "direct" | "proxy";
|
|
19
|
+
export type AgentRuntimeLocation = "server" | "bound-machine" | "local-host";
|
|
20
|
+
|
|
21
|
+
export type ProviderTransportDecision = {
|
|
22
|
+
mode: AgentProviderMode;
|
|
23
|
+
transport: ProviderExecutionTransport;
|
|
24
|
+
reason:
|
|
25
|
+
| "cli-provider"
|
|
26
|
+
| "custom-provider"
|
|
27
|
+
| "custom-server-proxy"
|
|
28
|
+
| "platform-agent"
|
|
29
|
+
| "forced-platform-env"
|
|
30
|
+
| "forced-direct-env"
|
|
31
|
+
| "direct-provider-env"
|
|
32
|
+
| "platform-proxy-fallback";
|
|
33
|
+
};
|
|
19
34
|
|
|
20
35
|
type ProviderExecutionPlanBase = {
|
|
21
36
|
mode: AgentProviderMode;
|
|
@@ -122,14 +137,50 @@ export function resolveAgentProviderMode(agentConfig: AgentRuntimeAgentConfig):
|
|
|
122
137
|
return "platform";
|
|
123
138
|
}
|
|
124
139
|
|
|
125
|
-
export function
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
export function resolveAgentRuntimeLocation(args: {
|
|
141
|
+
agentConfig: AgentRuntimeAgentConfig;
|
|
142
|
+
runtimeKind: "local" | "desktop" | "server";
|
|
143
|
+
}): AgentRuntimeLocation {
|
|
144
|
+
const runtimeBinding = args.agentConfig.runtimeBinding;
|
|
145
|
+
const machineId = typeof runtimeBinding?.machineId === "string"
|
|
146
|
+
? runtimeBinding.machineId.trim()
|
|
147
|
+
: "";
|
|
148
|
+
if (machineId) return "bound-machine";
|
|
149
|
+
if (args.runtimeKind === "server") return "server";
|
|
150
|
+
return "local-host";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function resolveProviderTransportDecision(args: {
|
|
154
|
+
agentConfig: AgentRuntimeAgentConfig;
|
|
155
|
+
env: EnvLike;
|
|
156
|
+
runtimeLocation: AgentRuntimeLocation;
|
|
157
|
+
}): ProviderTransportDecision {
|
|
158
|
+
const mode = resolveAgentProviderMode(args.agentConfig);
|
|
159
|
+
if (mode === "cli") {
|
|
160
|
+
return { mode, transport: "direct", reason: "cli-provider" };
|
|
161
|
+
}
|
|
162
|
+
if (mode === "custom") {
|
|
163
|
+
if (args.runtimeLocation === "server" && args.agentConfig.useServerProxy === true) {
|
|
164
|
+
return { mode, transport: "proxy", reason: "custom-server-proxy" };
|
|
165
|
+
}
|
|
166
|
+
return { mode, transport: "direct", reason: "custom-provider" };
|
|
167
|
+
}
|
|
168
|
+
if (args.agentConfig.apiSource === "platform" || args.agentConfig.useServerProxy === true) {
|
|
169
|
+
return { mode, transport: "proxy", reason: "platform-agent" };
|
|
170
|
+
}
|
|
171
|
+
if (args.env.NOLO_LOCAL_LLM === "platform") {
|
|
172
|
+
return { mode, transport: "proxy", reason: "forced-platform-env" };
|
|
173
|
+
}
|
|
174
|
+
if (args.env.NOLO_LOCAL_LLM === "direct") {
|
|
175
|
+
return { mode, transport: "direct", reason: "forced-direct-env" };
|
|
176
|
+
}
|
|
177
|
+
if (hasDirectOpenAiCompatibleProvider(args.env)) {
|
|
178
|
+
return { mode, transport: "direct", reason: "direct-provider-env" };
|
|
179
|
+
}
|
|
180
|
+
if (canUsePlatformChatProvider(args.env)) {
|
|
181
|
+
return { mode, transport: "proxy", reason: "platform-proxy-fallback" };
|
|
182
|
+
}
|
|
183
|
+
return { mode, transport: "direct", reason: "direct-provider-env" };
|
|
133
184
|
}
|
|
134
185
|
|
|
135
186
|
export function resolveProviderAuthHeaderName(args: {
|
|
@@ -161,6 +212,15 @@ export function buildProviderExecutionPlan(args: {
|
|
|
161
212
|
}): ProviderExecutionPlan {
|
|
162
213
|
const { agentConfig, env } = args;
|
|
163
214
|
const mode = resolveAgentProviderMode(agentConfig);
|
|
215
|
+
const runtimeLocation = resolveAgentRuntimeLocation({
|
|
216
|
+
agentConfig,
|
|
217
|
+
runtimeKind: args.runtimeKind,
|
|
218
|
+
});
|
|
219
|
+
const transportDecision = resolveProviderTransportDecision({
|
|
220
|
+
agentConfig,
|
|
221
|
+
env,
|
|
222
|
+
runtimeLocation,
|
|
223
|
+
});
|
|
164
224
|
const model = agentConfig.model || "gpt-4.1-mini";
|
|
165
225
|
const requestOptions = pickAgentRuntimeInferenceOptions(agentConfig);
|
|
166
226
|
|
|
@@ -182,7 +242,7 @@ export function buildProviderExecutionPlan(args: {
|
|
|
182
242
|
endpoint,
|
|
183
243
|
apiKeyHeader: agentConfig.apiKeyHeader,
|
|
184
244
|
});
|
|
185
|
-
if (
|
|
245
|
+
if (transportDecision.transport === "proxy") {
|
|
186
246
|
return {
|
|
187
247
|
mode,
|
|
188
248
|
transport: "proxy",
|
|
@@ -211,10 +271,10 @@ export function buildProviderExecutionPlan(args: {
|
|
|
211
271
|
}
|
|
212
272
|
|
|
213
273
|
const provider = agentConfig.provider || agentConfig.apiSource || "openai";
|
|
214
|
-
const endpoint =
|
|
274
|
+
const endpoint = transportDecision.transport === "proxy"
|
|
215
275
|
? resolvePlatformProviderEndpoint(agentConfig)
|
|
216
276
|
: resolveChatCompletionsEndpoint(resolveOpenAiCompatibleBaseUrl(env));
|
|
217
|
-
if (
|
|
277
|
+
if (transportDecision.transport === "proxy") {
|
|
218
278
|
return {
|
|
219
279
|
mode,
|
|
220
280
|
transport: "proxy",
|
|
@@ -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
|
}
|
|
@@ -96,6 +96,37 @@ function logConnectorRun(message: string, fields: Record<string, unknown> = {})
|
|
|
96
96
|
console.error(`[nolo-connector] ${message} ${JSON.stringify(fields)}`);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
function summarizeEndpoint(value: unknown) {
|
|
100
|
+
if (typeof value !== "string" || !value.trim()) return undefined;
|
|
101
|
+
try {
|
|
102
|
+
const url = new URL(value);
|
|
103
|
+
return `${url.protocol}//${url.host}${url.pathname}`;
|
|
104
|
+
} catch {
|
|
105
|
+
return "invalid-url";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function summarizeAgentConfigForLogs(agentConfig: any) {
|
|
110
|
+
const runtimeBinding = isRecord(agentConfig?.runtimeBinding) ? agentConfig.runtimeBinding : {};
|
|
111
|
+
return {
|
|
112
|
+
apiSource: agentConfig?.apiSource ?? null,
|
|
113
|
+
provider: agentConfig?.provider ?? null,
|
|
114
|
+
cliProvider: agentConfig?.cliProvider ?? null,
|
|
115
|
+
model: agentConfig?.model ?? null,
|
|
116
|
+
customProviderEndpoint: summarizeEndpoint(agentConfig?.customProviderUrl) ?? null,
|
|
117
|
+
useServerProxy: agentConfig?.useServerProxy ?? null,
|
|
118
|
+
skipLocalRuntimeEnsure: agentConfig?.skipLocalRuntimeEnsure ?? null,
|
|
119
|
+
hasApiKey: typeof agentConfig?.apiKey === "string" && agentConfig.apiKey.length > 0,
|
|
120
|
+
apiKeyHeader: agentConfig?.apiKeyHeader ?? null,
|
|
121
|
+
hasApiKeyFromAgentKey:
|
|
122
|
+
typeof agentConfig?.apiKeyFromAgentKey === "string" &&
|
|
123
|
+
agentConfig.apiKeyFromAgentKey.length > 0,
|
|
124
|
+
runtimeBindingKind: runtimeBinding.kind ?? null,
|
|
125
|
+
runtimeMachineId: runtimeBinding.machineId ?? null,
|
|
126
|
+
connectorSurface: runtimeBinding.connectorSurface ?? runtimeBinding.surface ?? null,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
99
130
|
function isRecord(value: unknown): value is Record<string, any> {
|
|
100
131
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
101
132
|
}
|
|
@@ -569,6 +600,15 @@ export async function handleConnectorRunMessage(
|
|
|
569
600
|
if (!requestsLocalWorkspaceRuntime(runtimePolicy) && !isMachineBoundLocalCustomProvider(agentConfig)) {
|
|
570
601
|
throw new Error("Connector can only execute non-CLI agents when runtimeToolPolicySnapshot requests a local workspace runtime.");
|
|
571
602
|
}
|
|
603
|
+
logConnectorRun("agent.run.local-runtime.start", {
|
|
604
|
+
requestId: parsed.requestId,
|
|
605
|
+
agentKey: parsed.payload?.agentKey,
|
|
606
|
+
cwd,
|
|
607
|
+
timeout,
|
|
608
|
+
machineBoundLocalCustomProvider: isMachineBoundLocalCustomProvider(agentConfig),
|
|
609
|
+
runtimePolicy: Boolean(runtimePolicy),
|
|
610
|
+
...summarizeAgentConfigForLogs(agentConfig),
|
|
611
|
+
});
|
|
572
612
|
baseSha = await readConnectorGitHead(cwd);
|
|
573
613
|
const result = await runConnectorLocalRuntimeAgent({
|
|
574
614
|
parsed,
|
|
@@ -607,6 +647,8 @@ export async function handleConnectorRunMessage(
|
|
|
607
647
|
logConnectorRun("agent.run.error", {
|
|
608
648
|
requestId: parsed.requestId,
|
|
609
649
|
agentKey: parsed.payload?.agentKey,
|
|
650
|
+
...summarizeAgentConfigForLogs(agentConfig),
|
|
651
|
+
errorName: error instanceof Error ? error.name : null,
|
|
610
652
|
error: error instanceof Error ? error.message : String(error),
|
|
611
653
|
});
|
|
612
654
|
send(JSON.stringify({
|
|
@@ -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
|
}
|
package/machineWsRunDispatch.ts
CHANGED
|
@@ -96,6 +96,37 @@ function logConnectorRun(message: string, fields: Record<string, unknown> = {})
|
|
|
96
96
|
console.error(`[nolo-connector] ${message} ${JSON.stringify(fields)}`);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
function summarizeEndpoint(value: unknown) {
|
|
100
|
+
if (typeof value !== "string" || !value.trim()) return undefined;
|
|
101
|
+
try {
|
|
102
|
+
const url = new URL(value);
|
|
103
|
+
return `${url.protocol}//${url.host}${url.pathname}`;
|
|
104
|
+
} catch {
|
|
105
|
+
return "invalid-url";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function summarizeAgentConfigForLogs(agentConfig: any) {
|
|
110
|
+
const runtimeBinding = isRecord(agentConfig?.runtimeBinding) ? agentConfig.runtimeBinding : {};
|
|
111
|
+
return {
|
|
112
|
+
apiSource: agentConfig?.apiSource ?? null,
|
|
113
|
+
provider: agentConfig?.provider ?? null,
|
|
114
|
+
cliProvider: agentConfig?.cliProvider ?? null,
|
|
115
|
+
model: agentConfig?.model ?? null,
|
|
116
|
+
customProviderEndpoint: summarizeEndpoint(agentConfig?.customProviderUrl) ?? null,
|
|
117
|
+
useServerProxy: agentConfig?.useServerProxy ?? null,
|
|
118
|
+
skipLocalRuntimeEnsure: agentConfig?.skipLocalRuntimeEnsure ?? null,
|
|
119
|
+
hasApiKey: typeof agentConfig?.apiKey === "string" && agentConfig.apiKey.length > 0,
|
|
120
|
+
apiKeyHeader: agentConfig?.apiKeyHeader ?? null,
|
|
121
|
+
hasApiKeyFromAgentKey:
|
|
122
|
+
typeof agentConfig?.apiKeyFromAgentKey === "string" &&
|
|
123
|
+
agentConfig.apiKeyFromAgentKey.length > 0,
|
|
124
|
+
runtimeBindingKind: runtimeBinding.kind ?? null,
|
|
125
|
+
runtimeMachineId: runtimeBinding.machineId ?? null,
|
|
126
|
+
connectorSurface: runtimeBinding.connectorSurface ?? runtimeBinding.surface ?? null,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
99
130
|
function isRecord(value: unknown): value is Record<string, any> {
|
|
100
131
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
101
132
|
}
|
|
@@ -569,6 +600,15 @@ export async function handleConnectorRunMessage(
|
|
|
569
600
|
if (!requestsLocalWorkspaceRuntime(runtimePolicy) && !isMachineBoundLocalCustomProvider(agentConfig)) {
|
|
570
601
|
throw new Error("Connector can only execute non-CLI agents when runtimeToolPolicySnapshot requests a local workspace runtime.");
|
|
571
602
|
}
|
|
603
|
+
logConnectorRun("agent.run.local-runtime.start", {
|
|
604
|
+
requestId: parsed.requestId,
|
|
605
|
+
agentKey: parsed.payload?.agentKey,
|
|
606
|
+
cwd,
|
|
607
|
+
timeout,
|
|
608
|
+
machineBoundLocalCustomProvider: isMachineBoundLocalCustomProvider(agentConfig),
|
|
609
|
+
runtimePolicy: Boolean(runtimePolicy),
|
|
610
|
+
...summarizeAgentConfigForLogs(agentConfig),
|
|
611
|
+
});
|
|
572
612
|
baseSha = await readConnectorGitHead(cwd);
|
|
573
613
|
const result = await runConnectorLocalRuntimeAgent({
|
|
574
614
|
parsed,
|
|
@@ -607,6 +647,8 @@ export async function handleConnectorRunMessage(
|
|
|
607
647
|
logConnectorRun("agent.run.error", {
|
|
608
648
|
requestId: parsed.requestId,
|
|
609
649
|
agentKey: parsed.payload?.agentKey,
|
|
650
|
+
...summarizeAgentConfigForLogs(agentConfig),
|
|
651
|
+
errorName: error instanceof Error ? error.name : null,
|
|
610
652
|
error: error instanceof Error ? error.message : String(error),
|
|
611
653
|
});
|
|
612
654
|
send(JSON.stringify({
|