Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ Current reality:

- Mirror now has an explicit package boundary, standalone Linux runtime artifact, extracted-artifact smoke, dist verification, and bootstrap verification.
- Package, bin, and release identity are materially more explicit and guarded than they were before the recent split-readiness PRs.
- The root OpenClaw script surface is now partially quarantined, but not fully removable yet because cleanup-smoke still depends on `pnpm openclaw ...`.
- This area should remain yellow because the package/build boundary is now real, but the remaining blockers are runtime ownership and observability rather than packaging viability.

### 8. CI gates before split
Expand Down
3 changes: 2 additions & 1 deletion src/mirror-gateway/mirror_gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export function createMirrorGateway(
options: {
observability?: Pick<
MirrorObservabilityContext,
"incrementMetric" | "incrementToolExecution" | "logEvent"
"incrementMetric" | "incrementToolExecution" | "recordLatency" | "logEvent"
>;
providerPlane?: MirrorProviderPlane;
policy?: MirrorPolicyEngine;
Expand Down Expand Up @@ -244,6 +244,7 @@ export function createMirrorGateway(
return executeMirrorChatWithProviderPlane(request, {
providerPlane,
fetchImpl: deps.fetchImpl,
observability: options.observability,
onRuntimeEvent: deps.onRuntimeEvent,
correlation: deps.correlation,
});
Expand Down
15 changes: 12 additions & 3 deletions src/mirror-provider/mirror_provider.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { logMirrorEvent, recordLatency } from "../mirror-observability/index.js";
import {
getCurrentMirrorObservabilityContext,
type MirrorObservabilityContext,
} from "../mirror-observability/index.js";
import { withMirrorCorrelation, type MirrorRuntimeCorrelation } from "../mirror-runtime/index.js";
import { buildMirrorProviderHeaders } from "./provider_auth.js";
import type { MirrorProviderConfig, MirrorProviderRequest } from "./provider_request.js";
import type { MirrorProviderResponse } from "./provider_response.js";

export type FetchLike = typeof fetch;
export type MirrorProviderObservability = Pick<
MirrorObservabilityContext,
"recordLatency" | "logEvent"
>;

export async function executeMirrorProviderRequest(
request: MirrorProviderRequest,
config: MirrorProviderConfig,
deps: {
fetchImpl?: FetchLike;
observability?: MirrorProviderObservability;
onRuntimeEvent?: (type: string, payload?: Record<string, unknown>) => void;
correlation?: Partial<MirrorRuntimeCorrelation>;
} = {},
Expand All @@ -32,6 +40,7 @@ export async function executeMirrorProviderRequest(
);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), config.timeoutMs ?? 30_000);
const observability = deps.observability ?? getCurrentMirrorObservabilityContext();

try {
const response = await (deps.fetchImpl ?? fetch)(config.url, {
Expand All @@ -48,7 +57,7 @@ export async function executeMirrorProviderRequest(

const payload = (await response.json()) as MirrorProviderResponse;
const durationMs = Date.now() - startedAt;
recordLatency("provider_latency_ms", durationMs);
observability.recordLatency("provider_latency_ms", durationMs);
deps.onRuntimeEvent?.(
"provider.call.finished",
withMirrorCorrelation(
Expand All @@ -60,7 +69,7 @@ export async function executeMirrorProviderRequest(
deps.correlation,
),
);
logMirrorEvent("provider.call", {
observability.logEvent("provider.call", {
url: config.url,
latency_ms: durationMs,
});
Expand Down
4 changes: 3 additions & 1 deletion src/mirror-provider/provider_plane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
type MirrorRuntimeCorrelation,
} from "../mirror-runtime/index.js";
import type { MirrorServiceConfig } from "../mirror-service/config.js";
import type { FetchLike } from "./mirror_provider.js";
import type { FetchLike, MirrorProviderObservability } from "./mirror_provider.js";
import { executeMirrorProviderRequest } from "./mirror_provider.js";
import type { MirrorProviderConfig, MirrorProviderRequest } from "./provider_request.js";
import type { MirrorProviderResponse } from "./provider_response.js";
Expand Down Expand Up @@ -66,6 +66,7 @@ export type MirrorProviderPlane = {
request: MirrorProviderRequest,
deps?: {
fetchImpl?: FetchLike;
observability?: MirrorProviderObservability;
onRuntimeEvent?: (type: string, payload?: Record<string, unknown>) => void;
selection?: MirrorProviderSelectionInput;
correlation?: Partial<MirrorRuntimeCorrelation>;
Expand Down Expand Up @@ -253,6 +254,7 @@ export function createMirrorProviderPlane(
toProviderConfig(entry.descriptor),
{
fetchImpl: deps.fetchImpl,
observability: deps.observability,
correlation,
onRuntimeEvent: (type, payload) => {
deps.onRuntimeEvent?.(type, withMirrorCorrelation(payload ?? {}, correlation));
Expand Down
26 changes: 22 additions & 4 deletions src/mirror-runtime/mirror_chat_engine.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { logMirrorEvent, recordLatency } from "../mirror-observability/index.js";
import {
getCurrentMirrorObservabilityContext,
type MirrorObservabilityContext,
} from "../mirror-observability/index.js";
import {
buildPrimaryProviderDescriptorFromConfig,
createMirrorProviderPlane,
Expand All @@ -16,6 +19,11 @@ import type {
MirrorPreparedChatRequest,
} from "./mirror_response.js";

type MirrorChatRuntimeObservability = Pick<
MirrorObservabilityContext,
"recordLatency" | "logEvent"
>;

function isDebugMode(): boolean {
const level = (process.env.MIRROR_LOG_LEVEL ?? "").toLowerCase();
return level === "debug" || level === "trace";
Expand Down Expand Up @@ -73,8 +81,12 @@ function resolveUserId(request: MirrorChatRequest): string | undefined {

export async function prepareMirrorChatRequest(
request: MirrorChatRequest,
deps: {
observability?: MirrorChatRuntimeObservability;
} = {},
): Promise<MirrorPreparedChatRequest> {
validateMirrorChatRequest(request);
const observability = deps.observability ?? getCurrentMirrorObservabilityContext();

const temperature =
request.temperature !== undefined ? Math.min(Math.max(request.temperature, 0), 1) : 0.7;
Expand All @@ -92,8 +104,8 @@ export async function prepareMirrorChatRequest(
userId: resolveUserId(request),
});
const retrievalDurationMs = Date.now() - retrievalStartedAt;
recordLatency("retrieval_time_ms", retrievalDurationMs);
logMirrorEvent("chat.retrieval", {
observability.recordLatency("retrieval_time_ms", retrievalDurationMs);
observability.logEvent("chat.retrieval", {
lore_dir: retrieval.diagnostics.loreDir,
returned_candidates: retrieval.candidates.length,
latency_ms: retrievalDurationMs,
Expand Down Expand Up @@ -163,6 +175,7 @@ export async function executeMirrorChatRequest(
export async function executeMirrorChatWithProvider(
request: MirrorChatRequest,
deps: {
observability?: MirrorChatRuntimeObservability;
provider: MirrorProviderConfig;
fetchImpl?: FetchLike;
onRuntimeEvent?: (type: string, payload?: Record<string, unknown>) => void;
Expand All @@ -180,13 +193,15 @@ export async function executeMirrorChatWithProvider(
return executeMirrorChatWithProviderPlane(request, {
providerPlane,
fetchImpl: deps.fetchImpl,
observability: deps.observability,
onRuntimeEvent: deps.onRuntimeEvent,
});
}

export async function executeMirrorChatWithProviderPlane(
request: MirrorChatRequest,
deps: {
observability?: MirrorChatRuntimeObservability;
providerPlane: MirrorProviderPlane;
fetchImpl?: FetchLike;
onRuntimeEvent?: (type: string, payload?: Record<string, unknown>) => void;
Expand All @@ -198,14 +213,17 @@ export async function executeMirrorChatWithProviderPlane(
};
},
): Promise<MirrorChatResponse> {
const prepared = await prepareMirrorChatRequest(request);
const prepared = await prepareMirrorChatRequest(request, {
observability: deps.observability,
});
const correlation = mergeMirrorCorrelation(request.correlation, deps.correlation, {
session_id: request.session?.session_id,
provider_id:
request.provider?.provider_id ?? deps.providerPlane.getActiveProvider()?.provider_id,
});
const execution = await deps.providerPlane.execute(prepared.modelRequest, {
fetchImpl: deps.fetchImpl,
observability: deps.observability,
onRuntimeEvent: deps.onRuntimeEvent,
correlation,
selection: {
Expand Down
3 changes: 0 additions & 3 deletions test/mirror-split-readiness-checklist-doc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ describe("mirror split-readiness checklist doc", () => {
expect(doc).toContain(
"Mirror now has an explicit package boundary, standalone Linux runtime artifact, extracted-artifact smoke, dist verification, and bootstrap verification.",
);
expect(doc).toContain(
"The root OpenClaw script surface is now partially quarantined, but not fully removable yet because cleanup-smoke still depends on `pnpm openclaw ...`.",
);

expect(doc).toContain("### 8. CI gates before split");
expect(doc).toContain(
Expand Down
Loading