bazis 0.99.1 → 0.99.2

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.
@@ -7,7 +7,8 @@ import { assertAgentToolHookIdV1, getAgentModuleContributionsV1, type AgentModul
7
7
  import type { AgentToolBeforeEffectEventV1, AgentToolEnforcementDecisionV1, AgentToolHookContextV1, AgentToolRequiredHookRefV1, AgentToolAuditHookProjectionV1, AgentToolSettlementEventV1 } from "./AgentToolHooks";
8
8
  import { agentModelJson } from "./internal/AgentModelBinding";
9
9
  import { redactSensitive, type SensitiveRedactionOptions } from "../../library/redaction";
10
- import { AgentSetupError, AgentToolExecutionError, AgentToolPreCommitError } from "./errors";
10
+ import { AgentSetupError, AgentToolExecutionError, AgentToolPreCommitError, ToolError } from "./errors";
11
+ import type { Logger } from "../kernel/logging/Logger";
11
12
  import type { AgentRegistry, ToolDefinition } from "./AgentRegistry";
12
13
  import type { JsonObject, JsonValue, AgentToolCall, AgentToolResult } from "./semantic";
13
14
  import { agentToolCall, agentToolResult, normalizeJsonValue } from "./semantic";
@@ -430,6 +431,8 @@ export class AgentToolExecutor {
430
431
  private readonly services: ServiceProvider,
431
432
  private readonly registry: AgentRegistry,
432
433
  options: AgentToolExecutorOptions = {},
434
+ /** Where unexpected tool failures go with their stack; the model sees a generic message. */
435
+ private readonly logger?: Logger,
433
436
  ) {
434
437
  assertNonNegativeInteger(options.defaultTimeoutMs, "AgentToolExecutor.defaultTimeoutMs");
435
438
  assertPositiveInteger(options.scopeDisposeTimeoutMs, "AgentToolExecutor.scopeDisposeTimeoutMs");
@@ -1530,15 +1533,12 @@ export class AgentToolExecutor {
1530
1533
  );
1531
1534
  });
1532
1535
  const code = this.interruptionCode(error, tool, executionState);
1536
+ if (code.endsWith("_OUTCOME_UNKNOWN")) {
1537
+ this.logger?.error("Agent tool outcome unknown", { agent: agentName ?? null, tool: call.name, callId: call.id, code, phase: executionState.phase });
1538
+ }
1533
1539
  return this.errorResult(call, code, executionState.timedOut ? "Tool execution timed out." : errorMessageOf(error), this.attemptMetadata(metadata, attempt), startedAt, { phase: executionState.phase });
1534
1540
  }
1535
- result = this.errorResult(
1536
- call,
1537
- "TOOL_EXECUTION_FAILED",
1538
- errorMessageOf(error),
1539
- this.attemptMetadata(metadata, attempt),
1540
- startedAt,
1541
- );
1541
+ result = this.failedResult(call, agentName, "TOOL_EXECUTION_FAILED", error, "Tool execution failed.", this.attemptMetadata(metadata, attempt), startedAt);
1542
1542
  } finally {
1543
1543
  detach?.();
1544
1544
  }
@@ -1582,13 +1582,7 @@ export class AgentToolExecutor {
1582
1582
  ? await contributed[0]!.activation.activateAsync(scope)
1583
1583
  : await scope.resolveAsync(tool.target);
1584
1584
  } catch (error) {
1585
- return this.errorResult(
1586
- call,
1587
- "TOOL_RESOLVE_FAILED",
1588
- `Tool resolve failed: ${errorMessageOf(error)}`,
1589
- this.attemptMetadata(metadata, attempt),
1590
- startedAt,
1591
- );
1585
+ return this.failedResult(call, agentName, "TOOL_RESOLVE_FAILED", error, "Tool could not be created.", this.attemptMetadata(metadata, attempt), startedAt);
1592
1586
  }
1593
1587
 
1594
1588
  if (signal.aborted) {
@@ -1638,12 +1632,14 @@ export class AgentToolExecutor {
1638
1632
  const explicitlyPreCommit = error instanceof AgentToolPreCommitError;
1639
1633
  const outcomeUnknown = !explicitlyPreCommit
1640
1634
  && (tool.metadata.sideEffect === "write" || tool.metadata.sideEffect === "external");
1641
- return this.errorResult(
1635
+ return this.failedResult(
1642
1636
  call,
1637
+ agentName,
1643
1638
  outcomeUnknown ? "TOOL_EXECUTION_FAILED_OUTCOME_UNKNOWN" : "TOOL_EXECUTION_FAILED",
1639
+ error,
1644
1640
  outcomeUnknown
1645
- ? `Tool "${tool.metadata.name}" threw after side-effect execution started; retry safety is unknown: ${errorMessageOf(error)}`
1646
- : errorMessageOf(error),
1641
+ ? `Tool "${tool.metadata.name}" threw after side-effect execution started; retry safety is unknown.`
1642
+ : "Tool execution failed.",
1647
1643
  this.attemptMetadata(metadata, attempt),
1648
1644
  startedAt,
1649
1645
  outcomeUnknown ? { sideEffect: tool.metadata.sideEffect, phase: "execute" } : undefined,
@@ -1664,13 +1660,7 @@ export class AgentToolExecutor {
1664
1660
  return this.postExecutionOutcome(
1665
1661
  call,
1666
1662
  tool,
1667
- this.errorResult(
1668
- call,
1669
- "TOOL_OUTPUT_INVALID",
1670
- `Tool output processing failed: ${errorMessageOf(error)}`,
1671
- this.attemptMetadata(metadata, attempt),
1672
- startedAt,
1673
- ),
1663
+ this.failedResult(call, agentName, "TOOL_OUTPUT_INVALID", error, "Tool output processing failed.", this.attemptMetadata(metadata, attempt), startedAt),
1674
1664
  metadata,
1675
1665
  startedAt,
1676
1666
  attempt,
@@ -1692,13 +1682,7 @@ export class AgentToolExecutor {
1692
1682
  return this.postExecutionOutcome(
1693
1683
  call,
1694
1684
  tool,
1695
- this.errorResult(
1696
- call,
1697
- "TOOL_RESULT_INVALID",
1698
- errorMessageOf(error),
1699
- this.attemptMetadata(metadata, attempt),
1700
- startedAt,
1701
- ),
1685
+ this.failedResult(call, agentName, "TOOL_RESULT_INVALID", error, "Tool result is invalid.", this.attemptMetadata(metadata, attempt), startedAt),
1702
1686
  metadata,
1703
1687
  startedAt,
1704
1688
  attempt,
@@ -2056,6 +2040,27 @@ export class AgentToolExecutor {
2056
2040
  }
2057
2041
 
2058
2042
 
2043
+ /**
2044
+ * A tool's own failure: a ToolError message reaches the model as written;
2045
+ * anything else is replaced by `fallback` and logged with its stack.
2046
+ */
2047
+ private failedResult(
2048
+ call: AgentToolCall,
2049
+ agentName: string | undefined,
2050
+ code: string,
2051
+ error: unknown,
2052
+ fallback: string,
2053
+ metadata: JsonObject,
2054
+ startedAt: number,
2055
+ details?: JsonObject,
2056
+ ): AgentToolResult {
2057
+ if (error instanceof ToolError) {
2058
+ return this.errorResult(call, code, error.message, metadata, startedAt, details);
2059
+ }
2060
+ this.logger?.error("Agent tool failed", { agent: agentName ?? null, tool: call.name, callId: call.id, code, error: redactSensitive(error) });
2061
+ return this.errorResult(call, code, fallback, metadata, startedAt, details);
2062
+ }
2063
+
2059
2064
  private errorResult(
2060
2065
  call: AgentToolCall,
2061
2066
  code: string,
@@ -100,6 +100,14 @@ Tool input and output are validated by the model validator
100
100
  otherwise. Audit entries redact `input`, `result` and execution `metadata`
101
101
  by default using `bazis/library/redaction`.
102
102
 
103
+ A tool reports a failure to the model with `throw new ToolError("Product
104
+ kiwi is no longer sold")`: the message reaches the model as written. Any other
105
+ exception from `execute` reaches the model as `Tool execution failed.` — internal
106
+ details stay out of the LLM — and goes to the application log with its stack
107
+ (`Agent tool failed`). Failures of the model itself are logged as `Agent model
108
+ call failed`. The LLM connectors pass the application logger; a runtime created
109
+ by hand takes `options.logger`.
110
+
103
111
  Retries are opt-in. `write` and `external` tools need an idempotency key before
104
112
  the executor repeats them. Runtime-generated keys include both the invocation id
105
113
  and the unique model call id; `toolExecution.idempotencyKeyForCall` gives a
@@ -22,12 +22,25 @@ export class AgentToolExecutionError extends Error {
22
22
  }
23
23
  }
24
24
 
25
+ /**
26
+ * A failure a tool reports to the model on purpose: the message reaches the
27
+ * model as written, so the model can explain it or try another way. Any other
28
+ * exception from `execute` reaches the model as "Tool execution failed." and
29
+ * goes to the application log with its stack.
30
+ */
31
+ export class ToolError extends Error {
32
+ constructor(message: string) {
33
+ super(message);
34
+ this.name = "ToolError";
35
+ }
36
+ }
37
+
25
38
  /**
26
39
  * Explicit assertion by a tool that execution failed before any side effect
27
40
  * could commit. Only this typed error keeps write/external failures eligible
28
- * for an idempotency-gated retry.
41
+ * for an idempotency-gated retry. Its message reaches the model like a ToolError.
29
42
  */
30
- export class AgentToolPreCommitError extends Error {
43
+ export class AgentToolPreCommitError extends ToolError {
31
44
  constructor(message: string) {
32
45
  super(message);
33
46
  this.name = "AgentToolPreCommitError";
@@ -15,6 +15,7 @@ export {
15
15
  AgentSetupError,
16
16
  AgentToolExecutionError,
17
17
  AgentToolPreCommitError,
18
+ ToolError,
18
19
  } from "./errors";
19
20
  export {
20
21
  AGENT_RUNTIME_OPTIONS,
@@ -3,6 +3,7 @@ import { describeTool } from "../Tool.contract";
3
3
  import type { ServiceProvider } from "../../di";
4
4
  import { getGeneratedOpenApiMetadata } from "../../http/OpenApi/generatedOpenApiRegistry";
5
5
  import { redactSensitive, redactSensitiveText } from "../../../library/redaction";
6
+ import type { Logger } from "../../kernel/logging/Logger";
6
7
  import { AgentRuntimeError } from "../errors";
7
8
  import { validateAgentJsonSchema } from "./AgentJsonSchema";
8
9
  import type { AgentDefinition, AgentRegistry } from "../AgentRegistry";
@@ -80,6 +81,11 @@ export interface AgentRuntimeOptions {
80
81
  readonly contextBuilder?: AgentContextBuilder;
81
82
  readonly contextLimits?: AgentContextLimits;
82
83
  readonly toolExecutorOptions?: AgentToolExecutorOptions;
84
+ /**
85
+ * Where failures of the model and unexpected tool failures go, with their
86
+ * stack. The LLM connectors pass the application logger.
87
+ */
88
+ readonly logger?: Logger;
83
89
  }
84
90
 
85
91
  export interface AgentRuntimeInvokeOptions {
@@ -503,6 +509,7 @@ export class AgentExecutionDriver {
503
509
  readonly defaultTimeoutMs?: number;
504
510
  private readonly defaultContextLimits?: AgentContextLimits;
505
511
  private readonly contextBuilder: AgentContextBuilder;
512
+ private readonly logger?: Logger;
506
513
 
507
514
  constructor(
508
515
  services: ServiceProvider,
@@ -521,7 +528,8 @@ export class AgentExecutionDriver {
521
528
  : options.timeoutMs ?? DEFAULT_MODEL_TIMEOUT_MS;
522
529
  this.defaultContextLimits = normalizeAgentContextLimits(options.contextLimits, "AgentRuntime.contextLimits");
523
530
  this.contextBuilder = options.contextBuilder ?? new DefaultAgentContextBuilder();
524
- this.toolExecutor = new AgentToolExecutor(services, registry, options.toolExecutorOptions);
531
+ this.logger = options.logger;
532
+ this.toolExecutor = new AgentToolExecutor(services, registry, options.toolExecutorOptions, options.logger);
525
533
  }
526
534
 
527
535
  async invoke(agentName: string, options: AgentRuntimeInvokeOptions = {}): Promise<AgentRuntimeResult> {
@@ -1122,6 +1130,7 @@ export class AgentExecutionDriver {
1122
1130
  try {
1123
1131
  return { ok: true, value: normalizeProviderResponse(rawResponse) };
1124
1132
  } catch (error) {
1133
+ this.logger?.error("Agent model call failed", { agent: agentName, invocationId: request.invocationId, code: "AGENT_PROVIDER_RESPONSE_INVALID", error: redactSensitive(error) });
1125
1134
  return {
1126
1135
  ok: false,
1127
1136
  error: runtimeError("AGENT_PROVIDER_RESPONSE_INVALID", `Model provider returned an invalid response: ${errorMessageOf(error)}`),
@@ -1133,6 +1142,9 @@ export class AgentExecutionDriver {
1133
1142
  : error instanceof AgentRuntimeAbortError
1134
1143
  ? "AGENT_ABORTED"
1135
1144
  : "AGENT_PROVIDER_FAILED";
1145
+ if (code !== "AGENT_ABORTED") {
1146
+ this.logger?.error("Agent model call failed", { agent: agentName, invocationId: request.invocationId, code, error: redactSensitive(error) });
1147
+ }
1136
1148
  return { ok: false, error: runtimeError(code, errorMessageOf(error)) };
1137
1149
  } finally {
1138
1150
  acceptingText = false;
@@ -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.1" }, capabilities: { experimentalApi: true },
235
+ clientInfo: { name: "bazis", title: "Bazis", version: "0.99.2" }, 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,7 @@
1
1
  import type { AppConfig, ConfigRegistry, Secret } from "../../kernel";
2
2
  import { AGENT_MODEL_PROVIDER, AGENT_RUNTIME_OPTIONS, AgentRuntime, type AgentModelProvider } from "../../agent";
3
3
  import { DI, SERVICE_PROVIDER, type ProviderDefinition } from "../../di";
4
+ import { LOGGER } from "../../kernel/logging/Logger";
4
5
  import { reader, requireValue } from "../connectorConfig";
5
6
  import { InfraError, type InfraConnector } from "../InfraConnector";
6
7
  import { identifyConnector } from "../connectorIdentity";
@@ -62,7 +63,8 @@ export function resolveLlmConnectionOptions<T extends LlmConfigShape>(
62
63
  export const agentRuntimeProviders: readonly ProviderDefinition[] = Object.freeze([
63
64
  DI.singleton(DI.factoryProviderWithResolver(AgentRuntime, [AGENT_MODEL_PROVIDER], (resolver, model: AgentModelProvider) => {
64
65
  const services = resolver.resolve(SERVICE_PROVIDER);
65
- return new AgentRuntime(services, model, services.has(AGENT_RUNTIME_OPTIONS) ? services.resolve(AGENT_RUNTIME_OPTIONS) : {});
66
+ const options = services.has(AGENT_RUNTIME_OPTIONS) ? services.resolve(AGENT_RUNTIME_OPTIONS) : {};
67
+ return new AgentRuntime(services, model, { ...options, logger: options.logger ?? services.tryResolve(LOGGER) });
66
68
  })),
67
69
  ]);
68
70
 
package/index.ts CHANGED
@@ -83,6 +83,7 @@ export {
83
83
  AgentRuntimeError,
84
84
  AgentSemanticError,
85
85
  AgentToolExecutionError,
86
+ ToolError,
86
87
  ApproximateAgentContextTokenEstimator,
87
88
  DefaultAgentContextBuilder,
88
89
  Tool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bazis",
3
- "version": "0.99.1",
3
+ "version": "0.99.2",
4
4
  "description": "Modular backend framework for Bun in TypeScript: DI wired by codegen, HTTP, a PostgreSQL ORM, JWT, WebSocket, agents and a CLI.",
5
5
  "license": "MIT",
6
6
  "author": "Alexander Alenin",