bazis 0.99.3 → 0.99.5
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/core/agent/AgentRuntime.ts +12 -0
- package/core/agent/AgentToolExecutor.ts +45 -8
- package/core/agent/ModelProvider.ts +6 -0
- package/core/agent/README.md +9 -0
- package/core/agent/errors.ts +11 -0
- package/core/agent/index.ts +1 -0
- package/core/agent/internal/AgentExecutionDriver.ts +2 -2
- package/core/infra/InfraLifecycle.ts +14 -1
- package/core/infra/connectors/codex/CodexAppServerClient.ts +1 -1
- package/core/infra/connectors/llmRouter.ts +23 -4
- package/core/infra/connectors/openaiCompatible.ts +2 -1
- package/index.ts +1 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createToken, type ServiceProvider } from "../di";
|
|
2
2
|
import { modelValidatorAdapter } from "../../library/validation";
|
|
3
|
+
import { AgentSetupError } from "./errors";
|
|
3
4
|
import type { AgentDataDefinition } from "./AgentDataDefinition";
|
|
4
5
|
import { AgentRegistry, type ToolDefinition } from "./AgentRegistry";
|
|
5
6
|
import {
|
|
@@ -62,6 +63,15 @@ export class AgentRuntime {
|
|
|
62
63
|
return this.catalog.listTools();
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
/** A profile the model provider does not serve fails before the model is called. */
|
|
67
|
+
private assertModelProfile(agentName: string, profile: string | undefined): void {
|
|
68
|
+
if (profile === undefined || typeof this.modelProvider.modelProfiles !== "function") return;
|
|
69
|
+
const configured = this.modelProvider.modelProfiles();
|
|
70
|
+
if (!configured.includes(profile)) {
|
|
71
|
+
throw new AgentSetupError(`Agent "${agentName}": model profile "${profile}" is not configured (configured: ${[...configured].sort().join(", ")}).`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
65
75
|
/**
|
|
66
76
|
* Checks a definition the way `run` does, without calling the model: an
|
|
67
77
|
* invalid field or a tool name not registered in `@Module.tools` throws
|
|
@@ -69,6 +79,7 @@ export class AgentRuntime {
|
|
|
69
79
|
*/
|
|
70
80
|
check(definition: AgentDataDefinition): void {
|
|
71
81
|
AgentRegistry.fromDefinition(definition, this.catalog.listTools());
|
|
82
|
+
this.assertModelProfile(definition.name, definition.modelProfile);
|
|
72
83
|
}
|
|
73
84
|
|
|
74
85
|
/**
|
|
@@ -78,6 +89,7 @@ export class AgentRuntime {
|
|
|
78
89
|
*/
|
|
79
90
|
async run(definition: AgentDataDefinition, options: AgentRuntimeInvokeOptions = {}): Promise<AgentRuntimeResult> {
|
|
80
91
|
const registry = AgentRegistry.fromDefinition(definition, this.catalog.listTools());
|
|
92
|
+
this.assertModelProfile(definition.name, options.modelProfile ?? definition.modelProfile);
|
|
81
93
|
const driver = new AgentExecutionDriver(this.services, registry, this.modelProvider, this.options);
|
|
82
94
|
return driver.invoke(definition.name, options);
|
|
83
95
|
}
|
|
@@ -811,7 +811,8 @@ export class AgentToolExecutor {
|
|
|
811
811
|
});
|
|
812
812
|
// Observer evidence is deliberately best effort and uses an independent
|
|
813
813
|
// bounded write: it cannot alter the already-terminal Tool result.
|
|
814
|
-
await awaitHook(Promise.resolve().then(() => auditSinkFunction(this.auditSink!)(entry)), undefined, timeoutMs);
|
|
814
|
+
const recorded = await awaitHook(Promise.resolve().then(() => auditSinkFunction(this.auditSink!)(entry)), undefined, timeoutMs);
|
|
815
|
+
if (recorded.kind !== "value") this.logAuditFailure("observer", settlement.toolName, settlement.callId, settlement.agentName, "best-effort", recorded);
|
|
815
816
|
}
|
|
816
817
|
|
|
817
818
|
private async executePipeline(
|
|
@@ -1195,8 +1196,12 @@ export class AgentToolExecutor {
|
|
|
1195
1196
|
if (!this.auditSink) return true;
|
|
1196
1197
|
try {
|
|
1197
1198
|
const outcome = await awaitHook(Promise.resolve().then(() => auditSinkFunction(this.auditSink!)({ kind: "agent-tool", phase, callId: call.id, toolName: tool.metadata.name, input: redactSensitive(normalizeJsonValue(call.input, "hook.audit.input"), this.hookRedaction), tool: { name: tool.metadata.name, sideEffect: tool.metadata.sideEffect, approval: tool.metadata.approval, tags: tool.metadata.tags ?? [] }, startedAtUnixMs: startedAt, finishedAtUnixMs: Date.now(), durationMs: Date.now() - startedAt, metadata: redactSensitive(metadata, this.hookRedaction) as JsonObject, hook })), signal, timeoutMs);
|
|
1199
|
+
if (outcome.kind !== "value") this.logAuditFailure(phase, call.name, call.id, options.agentName, "required", outcome);
|
|
1198
1200
|
return outcome.kind !== "value";
|
|
1199
|
-
} catch {
|
|
1201
|
+
} catch (error) {
|
|
1202
|
+
this.logAuditFailure(phase, call.name, call.id, options.agentName, "required", { kind: "failed", error });
|
|
1203
|
+
return true;
|
|
1204
|
+
}
|
|
1200
1205
|
}
|
|
1201
1206
|
|
|
1202
1207
|
private frameworkTerminalAuditTimeout(remainingMs: number | undefined): number {
|
|
@@ -1216,8 +1221,12 @@ export class AgentToolExecutor {
|
|
|
1216
1221
|
result: redactSensitive(result, this.hookRedaction) as AgentToolResult,
|
|
1217
1222
|
startedAtUnixMs: startedAt, finishedAtUnixMs: Date.now(), durationMs: Date.now() - startedAt,
|
|
1218
1223
|
})), signal, timeoutMs);
|
|
1224
|
+
if (outcome.kind !== "value") this.logAuditFailure("result", result.name, result.callId, undefined, "required", outcome);
|
|
1219
1225
|
return outcome.kind !== "value";
|
|
1220
|
-
} catch {
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
this.logAuditFailure("result", result.name, result.callId, undefined, "required", { kind: "failed", error });
|
|
1228
|
+
return true;
|
|
1229
|
+
}
|
|
1221
1230
|
}
|
|
1222
1231
|
|
|
1223
1232
|
private hasMandatoryHooks(): boolean {
|
|
@@ -1965,6 +1974,7 @@ export class AgentToolExecutor {
|
|
|
1965
1974
|
(error: unknown) => ({ ok: false, error } as const),
|
|
1966
1975
|
);
|
|
1967
1976
|
const outcome = await awaitHook(settled, signal, timeoutMs);
|
|
1977
|
+
if (outcome.kind === "timeout") this.logAuditFailure(entry.phase, entry.toolName, entry.callId, entry.agentName, audit.failureMode, outcome);
|
|
1968
1978
|
if (outcome.kind !== "value") return outcome;
|
|
1969
1979
|
return outcome.value.ok
|
|
1970
1980
|
? { kind: "value", value: undefined }
|
|
@@ -1980,6 +1990,8 @@ export class AgentToolExecutor {
|
|
|
1980
1990
|
originalResult: AgentToolResult | undefined,
|
|
1981
1991
|
error: unknown,
|
|
1982
1992
|
): AgentToolResult | undefined {
|
|
1993
|
+
// Logged in both modes: in best-effort the call goes on, and the lost entry is visible only here.
|
|
1994
|
+
this.logAuditFailure(entry.phase, entry.toolName, entry.callId, entry.agentName, audit.failureMode, { kind: "failed", error });
|
|
1983
1995
|
if (audit.failureMode === "best-effort") return undefined;
|
|
1984
1996
|
const sideEffectingSuccess = entry.phase === "result"
|
|
1985
1997
|
&& originalResult?.status === "success"
|
|
@@ -1991,8 +2003,8 @@ export class AgentToolExecutor {
|
|
|
1991
2003
|
call,
|
|
1992
2004
|
outcomeUnknown ? "TOOL_AUDIT_FAILED_OUTCOME_UNKNOWN" : "TOOL_AUDIT_FAILED",
|
|
1993
2005
|
outcomeUnknown
|
|
1994
|
-
?
|
|
1995
|
-
:
|
|
2006
|
+
? "Tool result audit failed after an outcome-unknown side-effecting operation; retry safety is unknown."
|
|
2007
|
+
: "Tool audit failed.",
|
|
1996
2008
|
metadata,
|
|
1997
2009
|
startedAt,
|
|
1998
2010
|
{
|
|
@@ -2042,12 +2054,12 @@ export class AgentToolExecutor {
|
|
|
2042
2054
|
.then(async (result) => {
|
|
2043
2055
|
const error = await this.disposeScope(scope, scopeDisposeTimeoutMs);
|
|
2044
2056
|
if (error !== undefined) {
|
|
2045
|
-
|
|
2057
|
+
this.reportDeferred("Agent tool scope disposal failed", { tool: call.name, callId: call.id, error: redactSensitive(error) });
|
|
2046
2058
|
}
|
|
2047
2059
|
await onSettled(result);
|
|
2048
2060
|
})
|
|
2049
2061
|
.catch((error: unknown) => {
|
|
2050
|
-
|
|
2062
|
+
this.reportDeferred("Agent tool settlement handling failed", { tool: call.name, callId: call.id, error: redactSensitive(error) });
|
|
2051
2063
|
});
|
|
2052
2064
|
}
|
|
2053
2065
|
|
|
@@ -2056,11 +2068,36 @@ export class AgentToolExecutor {
|
|
|
2056
2068
|
try {
|
|
2057
2069
|
await auditSinkFunction(audit.sink)(entry);
|
|
2058
2070
|
} catch (error) {
|
|
2059
|
-
|
|
2071
|
+
this.logAuditFailure(entry.phase, entry.toolName, entry.callId, entry.agentName, audit.failureMode, { kind: "failed", error });
|
|
2060
2072
|
}
|
|
2061
2073
|
}
|
|
2062
2074
|
|
|
2063
2075
|
|
|
2076
|
+
/**
|
|
2077
|
+
* The audit sink did not record an entry. `mode` is how the call treated it:
|
|
2078
|
+
* `fail-closed` stopped it, `best-effort` let it go on, `required` is hook evidence.
|
|
2079
|
+
*/
|
|
2080
|
+
private logAuditFailure(
|
|
2081
|
+
phase: string,
|
|
2082
|
+
toolName: string,
|
|
2083
|
+
callId: string,
|
|
2084
|
+
agentName: string | undefined,
|
|
2085
|
+
mode: AgentToolAuditFailureMode | "required",
|
|
2086
|
+
outcome: HookOutcome<unknown>,
|
|
2087
|
+
): void {
|
|
2088
|
+
if (outcome.kind === "value" || outcome.kind === "cancelled") return;
|
|
2089
|
+
this.logger?.error("Agent tool audit failed", {
|
|
2090
|
+
phase, mode, agent: agentName ?? null, tool: toolName, callId,
|
|
2091
|
+
...(outcome.kind === "timeout" ? { reason: "timed out" } : outcome.error === undefined ? {} : { error: redactSensitive(outcome.error) }),
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
/** Late failures after the call returned; without an application logger they still reach stderr. */
|
|
2096
|
+
private reportDeferred(message: string, fields: Record<string, unknown>): void {
|
|
2097
|
+
if (this.logger) this.logger.error(message, fields);
|
|
2098
|
+
else console.error(`[agent-tool] ${message}`, fields);
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2064
2101
|
/** A hook that failed, timed out or answered nonsense; a cancelled run is not a failure. */
|
|
2065
2102
|
private logHookFailure(
|
|
2066
2103
|
hook: Pick<AgentToolAuditHookProjectionV1, "kind" | "id" | "version" | "outcome">,
|
|
@@ -16,6 +16,12 @@ export interface AgentModelProvider {
|
|
|
16
16
|
request: AgentModelRequest,
|
|
17
17
|
context: AgentModelProviderContext,
|
|
18
18
|
): AgentModelResponse | Promise<AgentModelResponse>;
|
|
19
|
+
/**
|
|
20
|
+
* Model profiles this provider serves, when it routes by profile
|
|
21
|
+
* (`llmRouter`). AgentRuntime rejects an agent naming another profile before
|
|
22
|
+
* the model is called. Without it any profile is passed through.
|
|
23
|
+
*/
|
|
24
|
+
modelProfiles?(): readonly string[];
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
export const AGENT_MODEL_PROVIDER = createToken<AgentModelProvider>("AgentModelProvider");
|
package/core/agent/README.md
CHANGED
|
@@ -115,6 +115,10 @@ audit. A hook that throws, times out or returns an invalid answer is logged as
|
|
|
115
115
|
`AgentRuntime` at start, so wrong runtime options or enforcement hooks without
|
|
116
116
|
an audit sink stop the application with a configuration error.
|
|
117
117
|
|
|
118
|
+
An audit sink that fails is logged as `Agent tool audit failed` with the
|
|
119
|
+
phase and mode, in `best-effort` too, where the call goes on; the model sees
|
|
120
|
+
only `Tool audit failed.`.
|
|
121
|
+
|
|
118
122
|
Retries are opt-in. `write` and `external` tools need an idempotency key before
|
|
119
123
|
the executor repeats them. Runtime-generated keys include both the invocation id
|
|
120
124
|
and the unique model call id; `toolExecution.idempotencyKeyForCall` gives a
|
|
@@ -139,6 +143,11 @@ await this.agents.run(support, {
|
|
|
139
143
|
conversation message when trimming old history. Provider requests include
|
|
140
144
|
`metadata.agentContext.trace` so context assembly is inspectable.
|
|
141
145
|
|
|
146
|
+
With `llmRouter`, `check` and `run` reject a `modelProfile` the router does
|
|
147
|
+
not serve; a fallback to another profile is logged as `LLM model profile
|
|
148
|
+
failed, using fallback`. A model provider that gives up after its own deadline
|
|
149
|
+
throws `AgentModelTimeoutError`, and the run reports `AGENT_PROVIDER_TIMEOUT`.
|
|
150
|
+
|
|
142
151
|
LLM clients are registered by infra connectors. Agents name a model profile;
|
|
143
152
|
infra owns provider URLs, model ids, limits and fallback:
|
|
144
153
|
|
package/core/agent/errors.ts
CHANGED
|
@@ -47,6 +47,17 @@ export class AgentToolPreCommitError extends ToolError {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* A model provider gave up on a request after its own deadline (for example
|
|
52
|
+
* the connector's `timeoutMs`). The run reports it as AGENT_PROVIDER_TIMEOUT.
|
|
53
|
+
*/
|
|
54
|
+
export class AgentModelTimeoutError extends Error {
|
|
55
|
+
constructor(message: string) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = "AgentModelTimeoutError";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
50
61
|
/** Error thrown when the agent runtime is configured incorrectly. */
|
|
51
62
|
export class AgentRuntimeError extends Error {
|
|
52
63
|
constructor(message: string) {
|
package/core/agent/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { ServiceProvider } from "../../di";
|
|
|
4
4
|
import { getGeneratedOpenApiMetadata } from "../../http/OpenApi/generatedOpenApiRegistry";
|
|
5
5
|
import { redactSensitive, redactSensitiveText } from "../../../library/redaction";
|
|
6
6
|
import type { Logger } from "../../kernel/logging/Logger";
|
|
7
|
-
import { AgentRuntimeError } from "../errors";
|
|
7
|
+
import { AgentModelTimeoutError, AgentRuntimeError } from "../errors";
|
|
8
8
|
import { validateAgentJsonSchema } from "./AgentJsonSchema";
|
|
9
9
|
import type { AgentDefinition, AgentRegistry } from "../AgentRegistry";
|
|
10
10
|
import {
|
|
@@ -1137,7 +1137,7 @@ export class AgentExecutionDriver {
|
|
|
1137
1137
|
};
|
|
1138
1138
|
}
|
|
1139
1139
|
} catch (error) {
|
|
1140
|
-
const code = error instanceof AgentRuntimeTimeoutError
|
|
1140
|
+
const code = error instanceof AgentRuntimeTimeoutError || error instanceof AgentModelTimeoutError
|
|
1141
1141
|
? "AGENT_PROVIDER_TIMEOUT"
|
|
1142
1142
|
: error instanceof AgentRuntimeAbortError
|
|
1143
1143
|
? "AGENT_ABORTED"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HostedService } from "../di";
|
|
1
|
+
import type { HostedService, HostedServiceDiagnostics } from "../di";
|
|
2
2
|
import { InfraError, type InfraConnector } from "./InfraConnector";
|
|
3
3
|
import { bindConnectorLifecycle } from "./connectorIdentity";
|
|
4
4
|
import { awaitAbortable } from "../kernel/internal/awaitAbortable";
|
|
@@ -22,6 +22,7 @@ export class InfraLifecycle<TClient> implements HostedService {
|
|
|
22
22
|
private disposed = false;
|
|
23
23
|
private startPromise?: Promise<void>;
|
|
24
24
|
private disposePromise?: Promise<void>;
|
|
25
|
+
private diagnostics?: HostedServiceDiagnostics;
|
|
25
26
|
|
|
26
27
|
public constructor(
|
|
27
28
|
private readonly name: string,
|
|
@@ -40,10 +41,22 @@ export class InfraLifecycle<TClient> implements HostedService {
|
|
|
40
41
|
if (!this.created) {
|
|
41
42
|
this.client = this.connector.create(this.configs);
|
|
42
43
|
this.created = true;
|
|
44
|
+
this.forwardDiagnostics();
|
|
43
45
|
}
|
|
44
46
|
return this.client as TClient;
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
/** The application logger reaches a client that reports on its own, such as `llmRouter` falling back. */
|
|
50
|
+
public useDiagnostics(diagnostics: HostedServiceDiagnostics): void {
|
|
51
|
+
this.diagnostics = diagnostics;
|
|
52
|
+
if (this.created) this.forwardDiagnostics();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private forwardDiagnostics(): void {
|
|
56
|
+
const client = this.client as { useDiagnostics?: (diagnostics: HostedServiceDiagnostics) => void } | undefined;
|
|
57
|
+
if (this.diagnostics !== undefined && typeof client?.useDiagnostics === "function") client.useDiagnostics(this.diagnostics);
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
public start(signal?: AbortSignal): Promise<void> {
|
|
48
61
|
this.startPromise ??= Promise.resolve().then(() => this.connect(signal));
|
|
49
62
|
return this.startPromise;
|
|
@@ -232,7 +232,7 @@ export class CodexAppServerClient implements CodexClient {
|
|
|
232
232
|
if (method === "account/updated") this.modelCache = undefined;
|
|
233
233
|
}, () => { this.clearLogin(); this.modelCache = undefined; });
|
|
234
234
|
const initialized = await client.request("initialize", {
|
|
235
|
-
clientInfo: { name: "bazis", title: "Bazis", version: "0.99.
|
|
235
|
+
clientInfo: { name: "bazis", title: "Bazis", version: "0.99.5" }, capabilities: { experimentalApi: true },
|
|
236
236
|
}, 15_000, signal);
|
|
237
237
|
if (resolve(text(initialized.codexHome, 4096)) !== this.paths.home) throw new CodexError("PROTOCOL_ERROR");
|
|
238
238
|
client.notify("initialized");
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { AppConfig } from "../../kernel";
|
|
2
|
+
import type { HostedServiceDiagnostics } from "../../di";
|
|
3
|
+
import { redactSensitive } from "../../../library/redaction";
|
|
2
4
|
import {
|
|
3
5
|
AGENT_MODEL_PROVIDER,
|
|
6
|
+
AgentModelTimeoutError,
|
|
4
7
|
AgentRuntime,
|
|
5
8
|
agentModelRequest,
|
|
6
9
|
type AgentModelProvider,
|
|
@@ -194,11 +197,13 @@ export class LlmModelRouter implements AgentModelProvider {
|
|
|
194
197
|
private initializePromise?: Promise<void>;
|
|
195
198
|
private disposePromise?: Promise<void>;
|
|
196
199
|
private disposed = false;
|
|
200
|
+
private diagnostics?: HostedServiceDiagnostics;
|
|
197
201
|
|
|
198
202
|
public constructor(
|
|
199
203
|
profiles: readonly RuntimeProfile[],
|
|
200
204
|
private readonly defaultProfile: string,
|
|
201
205
|
private readonly factories: readonly (() => RuntimeProfile)[] = [],
|
|
206
|
+
private readonly profileNames: readonly string[] = profiles.map((profile) => profile.name),
|
|
202
207
|
) {
|
|
203
208
|
for (let index = 0; index < profiles.length; index += 1) {
|
|
204
209
|
const profile = profiles[index] as RuntimeProfile;
|
|
@@ -213,6 +218,16 @@ export class LlmModelRouter implements AgentModelProvider {
|
|
|
213
218
|
return this.completeWithProfile(request, context, requested, new Set<string>());
|
|
214
219
|
}
|
|
215
220
|
|
|
221
|
+
/** Profile names an agent may use in `modelProfile`. */
|
|
222
|
+
public modelProfiles(): readonly string[] {
|
|
223
|
+
return this.profileNames;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** The application logger: a fallback is reported, not silent. */
|
|
227
|
+
public useDiagnostics(diagnostics: HostedServiceDiagnostics): void {
|
|
228
|
+
this.diagnostics = diagnostics;
|
|
229
|
+
}
|
|
230
|
+
|
|
216
231
|
public connect(signal?: AbortSignal): Promise<void> {
|
|
217
232
|
if (this.disposed) {
|
|
218
233
|
return Promise.reject(new InfraError("LLM model router is already disposed."));
|
|
@@ -363,11 +378,15 @@ export class LlmModelRouter implements AgentModelProvider {
|
|
|
363
378
|
// A second model must not silently append a new answer to already visible text.
|
|
364
379
|
if (fallback !== undefined && !emittedText) {
|
|
365
380
|
if (context.signal.aborted) throw new LlmModelRouterError("LLM model request was cancelled before provider dispatch.");
|
|
381
|
+
this.diagnostics?.warn("LLM model profile failed, using fallback", {
|
|
382
|
+
profile: profileName, fallback, agent: context.agentName, invocationId: context.invocationId, error: redactSensitive(error),
|
|
383
|
+
});
|
|
366
384
|
return this.completeWithProfile(request, context, fallback, visited);
|
|
367
385
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
);
|
|
386
|
+
const message = `LLM model profile "${profileName}" failed: ${errorMessageOf(error)}`;
|
|
387
|
+
// Keep a timeout a timeout: the run reports it as AGENT_PROVIDER_TIMEOUT.
|
|
388
|
+
if (error instanceof AgentModelTimeoutError) throw new AgentModelTimeoutError(message);
|
|
389
|
+
throw new LlmModelRouterError(message);
|
|
371
390
|
} finally {
|
|
372
391
|
acceptingText = false;
|
|
373
392
|
}
|
|
@@ -432,7 +451,7 @@ export function llmRouter(
|
|
|
432
451
|
options: profile.options,
|
|
433
452
|
});
|
|
434
453
|
});
|
|
435
|
-
return new LlmModelRouter([], defaultProfile, factories);
|
|
454
|
+
return new LlmModelRouter([], defaultProfile, factories, entries.map(([name]) => name));
|
|
436
455
|
},
|
|
437
456
|
connect(client, signal) {
|
|
438
457
|
return client instanceof LlmModelRouter ? client.connect(signal) : undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AgentModelTimeoutError,
|
|
2
3
|
agentMessage,
|
|
3
4
|
agentModelResponse,
|
|
4
5
|
agentToolCall,
|
|
@@ -490,7 +491,7 @@ export class OpenAiCompatibleModelProvider implements AgentModelProvider {
|
|
|
490
491
|
const detach = attachAbortForwarding(signal ? AbortSignal.any([signal, this.lifetime.signal]) : this.lifetime.signal, abort);
|
|
491
492
|
const timeout = this.requestTimeoutMs === undefined
|
|
492
493
|
? undefined
|
|
493
|
-
: setTimeout(() => abort.abort(new
|
|
494
|
+
: setTimeout(() => abort.abort(new AgentModelTimeoutError("OpenAI-compatible request timed out.")), this.requestTimeoutMs);
|
|
494
495
|
try {
|
|
495
496
|
abort.signal.throwIfAborted();
|
|
496
497
|
const response = await this.fetcher(`${this.baseUrl}${path}`, {
|
package/index.ts
CHANGED
package/package.json
CHANGED