@tonyclaw/agent-inspector 2.0.1 → 2.0.3

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.
Files changed (53) hide show
  1. package/.output/cli.js +344 -53
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-sVLGhCO3.js → CompareDrawer-D5A4bTfV.js} +1 -1
  4. package/.output/public/assets/ProxyViewerContainer-Da0jpBkp.js +101 -0
  5. package/.output/public/assets/{ReplayDialog-DxbFUqNW.js → ReplayDialog-CxUk_TF0.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-CSmGQa_g.js → RequestAnatomy-DIlzjgjJ.js} +1 -1
  7. package/.output/public/assets/ResponseView-DQCuKJ1G.js +1 -0
  8. package/.output/public/assets/{StreamingChunkSequence-BzqpY0TN.js → StreamingChunkSequence-DHk4SGGL.js} +1 -1
  9. package/.output/public/assets/_sessionId-dY1TTl7N.js +1 -0
  10. package/.output/public/assets/index-D7wwbwly.css +1 -0
  11. package/.output/public/assets/index-FqQZbfl2.js +1 -0
  12. package/.output/public/assets/{json-viewer-CKNMihlh.js → json-viewer-BbU0n8eM.js} +1 -1
  13. package/.output/public/assets/{main-yWf8dv9w.js → main-CZT_F-gu.js} +2 -2
  14. package/.output/server/_libs/lucide-react.mjs +8 -8
  15. package/.output/server/{_sessionId-DfHd0gd8.mjs → _sessionId-B-s9P7fJ.mjs} +2 -2
  16. package/.output/server/_ssr/{CompareDrawer-DGYAUWgF.mjs → CompareDrawer-C08L3UOO.mjs} +4 -4
  17. package/.output/server/_ssr/{ProxyViewerContainer-fawglkTo.mjs → ProxyViewerContainer-CMWl3Ijy.mjs} +414 -70
  18. package/.output/server/_ssr/{ReplayDialog-B4vlKa2W.mjs → ReplayDialog-CPDo9_G5.mjs} +4 -4
  19. package/.output/server/_ssr/{RequestAnatomy-BNQvEIZK.mjs → RequestAnatomy-D9wt_K1E.mjs} +3 -3
  20. package/.output/server/_ssr/{ResponseView-X6X6G16_.mjs → ResponseView-DXaL7nY3.mjs} +4 -4
  21. package/.output/server/_ssr/{StreamingChunkSequence-BPVN3MnF.mjs → StreamingChunkSequence-B_hudZyb.mjs} +3 -3
  22. package/.output/server/_ssr/{index-CXmpc2X5.mjs → index-CuE_BN86.mjs} +2 -2
  23. package/.output/server/_ssr/index.mjs +2 -2
  24. package/.output/server/_ssr/{json-viewer-3XC3eq4R.mjs → json-viewer-Ci6kkjde.mjs} +2 -2
  25. package/.output/server/_ssr/{router-C0B2qvIM.mjs → router-BemxgIg7.mjs} +402 -131
  26. package/.output/server/{_tanstack-start-manifest_v-7tfsmd2I.mjs → _tanstack-start-manifest_v--L1_b4sd.mjs} +1 -1
  27. package/.output/server/index.mjs +62 -62
  28. package/README.md +50 -7
  29. package/package.json +3 -2
  30. package/scripts/setup-codex-skill.mjs +38 -0
  31. package/scripts/setup-windows-runtime.mjs +4 -3
  32. package/src/cli/onboard.ts +175 -68
  33. package/src/cli/templates/codex-skill-onboard.ts +210 -0
  34. package/src/components/providers/ProviderCard.tsx +2 -27
  35. package/src/components/providers/ProvidersPanel.tsx +16 -0
  36. package/src/components/proxy-viewer/AgentTraceSummary.tsx +218 -0
  37. package/src/components/proxy-viewer/ConversationGroup.tsx +6 -0
  38. package/src/components/proxy-viewer/ToolTraceEvents.tsx +33 -0
  39. package/src/components/proxy-viewer/TurnGroup.tsx +11 -1
  40. package/src/components/proxy-viewer/viewerState.ts +177 -0
  41. package/src/knowledge/openclawClient.ts +34 -5
  42. package/src/knowledge/openclawGatewayClient.ts +237 -0
  43. package/src/knowledge/openclawMarkdown.ts +146 -0
  44. package/src/lib/providerTestPrompt.ts +78 -0
  45. package/src/proxy/chunkStorage.ts +3 -4
  46. package/src/proxy/logger.ts +8 -15
  47. package/src/proxy/store.ts +8 -16
  48. package/src/routes/api/providers.$providerId.test.log.ts +7 -99
  49. package/.output/public/assets/ProxyViewerContainer-p9QvzZ6U.js +0 -101
  50. package/.output/public/assets/ResponseView-B5f89c8Z.js +0 -1
  51. package/.output/public/assets/_sessionId-BF7ftHV3.js +0 -1
  52. package/.output/public/assets/index-BU0PpLby.js +0 -1
  53. package/.output/public/assets/index-CpWG2hFn.css +0 -1
@@ -2,7 +2,7 @@ import { c as createRouter, a as createRootRoute, b as createFileRoute, l as laz
2
2
  import { j as jsxRuntimeExports } from "../_libs/react.mjs";
3
3
  import { S as SWRConfig } from "../_libs/swr.mjs";
4
4
  import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync, copyFileSync, unlinkSync } from "node:fs";
5
- import { mkdir, appendFile, readFile, open, readdir, stat, unlink, writeFile } from "node:fs/promises";
5
+ import fs, { mkdir, appendFile, readFile, open, readdir, stat, unlink, writeFile } from "node:fs/promises";
6
6
  import { Buffer } from "node:buffer";
7
7
  import path, { join, isAbsolute, dirname } from "node:path";
8
8
  import { execFile, exec, spawn } from "node:child_process";
@@ -13,7 +13,7 @@ import { promisify } from "node:util";
13
13
  import { Worker } from "node:worker_threads";
14
14
  import { M as McpServer, W as WebStandardStreamableHTTPServerTransport } from "../_libs/modelcontextprotocol__server.mjs";
15
15
  import { homedir } from "node:os";
16
- import { d as object, b as string, a as array, _ as _enum, u as union, n as number, c as boolean, l as literal, r as record, g as discriminatedUnion, h as _null, k as lazy, e as unknown } from "../_libs/zod.mjs";
16
+ import { d as object, b as string, a as array, _ as _enum, u as union, n as number, c as boolean, e as unknown, l as literal, r as record, g as discriminatedUnion, h as _null, k as lazy } from "../_libs/zod.mjs";
17
17
  import "../_libs/tiny-warning.mjs";
18
18
  import "../_libs/tanstack__router-core.mjs";
19
19
  import "../_libs/cookie-es.mjs";
@@ -49,7 +49,7 @@ import "../_libs/mimic-function.mjs";
49
49
  import "../_libs/semver.mjs";
50
50
  import "../_libs/uint8array-extras.mjs";
51
51
  const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2064%2064'%20role='img'%20aria-label='Agent%20Inspector'%3e%3crect%20width='64'%20height='64'%20rx='14'%20fill='%23111827'%20/%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='4.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20fill='%23f59e0b'%20d='M15%2036c0-11%207-18%2017-18s17%207%2017%2018c0%208-7%2013-17%2013s-17-5-17-13z'%20/%3e%3cpath%20d='M16%2031c-6-5-12-3-12%204%200%205%206%206%2011%202'%20/%3e%3cpath%20d='M48%2031c6-5%2012-3%2012%204%200%205-6%206-11%202'%20/%3e%3cpath%20d='M27%2019l-3-7'%20/%3e%3cpath%20d='M37%2019l3-7'%20/%3e%3cpath%20d='M19%2045l-6%209'%20/%3e%3cpath%20d='M27%2048l-3%209'%20/%3e%3cpath%20d='M37%2048l3%209'%20/%3e%3cpath%20d='M45%2045l6%209'%20/%3e%3c/g%3e%3cpath%20d='M14%2047l9-8%208%209c-5%203.5-12%203-17-1z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M18%2046l5-5%205%206c-3%201.6-7%201.4-10-1z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M23%2041v10'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.6'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='31'%20cy='48'%20r='1.8'%20fill='%23c2412d'%20/%3e%3cpath%20d='M24%2044l13-11%2014%2013c-8%205.8-18%205.3-27-2z'%20fill='%232f6b3f'%20opacity='.97'%20/%3e%3cpath%20d='M30%2043l7-7%209%209c-5%202.7-11%202.5-16-2z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M37%2036v14'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='2'%20stroke-linecap='round'%20/%3e%3cpath%20d='M30%2043c5-2%2011-1.5%2016%202'%20fill='none'%20stroke='%239fca78'%20stroke-width='1.8'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='51'%20cy='46'%20r='2'%20fill='%23c2412d'%20/%3e%3cpath%20d='M40%2050l8-8%207%208c-4.2%203.2-10%203-15%200z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M43%2049l5-5%204.5%205.5c-3%201.5-6%201.2-9.5-.5z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M48%2044v9'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.5'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='55'%20cy='50'%20r='1.7'%20fill='%23c2412d'%20/%3e%3ccircle%20cx='24'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='40'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='25'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3ccircle%20cx='39'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3c/svg%3e";
52
- const appCss = "/assets/index-CpWG2hFn.css";
52
+ const appCss = "/assets/index-D7wwbwly.css";
53
53
  const Route$q = createRootRoute({
54
54
  head: () => ({
55
55
  meta: [
@@ -76,7 +76,7 @@ function RootDocument({ children }) {
76
76
  ] })
77
77
  ] });
78
78
  }
79
- const $$splitComponentImporter$1 = () => import("./index-CXmpc2X5.mjs");
79
+ const $$splitComponentImporter$1 = () => import("./index-CuE_BN86.mjs");
80
80
  const Route$p = createFileRoute("/")({
81
81
  component: lazyRouteComponent($$splitComponentImporter$1, "component")
82
82
  });
@@ -119,7 +119,7 @@ function decodeSessionIdFromPath(encoded) {
119
119
  function getSessionPath(sessionId) {
120
120
  return `/session/${encodeSessionIdForPath(sessionId)}`;
121
121
  }
122
- const $$splitComponentImporter = () => import("../_sessionId-DfHd0gd8.mjs");
122
+ const $$splitComponentImporter = () => import("../_sessionId-B-s9P7fJ.mjs");
123
123
  const Route$o = createFileRoute("/session/$sessionId")({
124
124
  component: lazyRouteComponent($$splitComponentImporter, "component"),
125
125
  parseParams: (params) => ({
@@ -155,18 +155,13 @@ function resolveDataDir(pathExists, env = process.env, platform = process.platfo
155
155
  function hasExplicitDataDir() {
156
156
  return process.env["AGENT_INSPECTOR_DATA_DIR"] !== void 0 && process.env["AGENT_INSPECTOR_DATA_DIR"] !== "" || process.env["AGENT_INSPECTOR_CONFIG_DIR"] !== void 0 && process.env["AGENT_INSPECTOR_CONFIG_DIR"] !== "";
157
157
  }
158
- const LOG_DIR_ENV = process.env["LOG_DIR"];
159
158
  const RETENTION_DAYS = Number(process.env["LOG_RETENTION_DAYS"] ?? "7");
160
- const LOG_FILE_ENV = process.env["AGENT_INSPECTOR_LOG_FILE"];
161
- let resolvedLogDir = null;
162
159
  function resolveLogDir() {
163
- if (resolvedLogDir !== null) return resolvedLogDir;
164
- if (LOG_DIR_ENV !== void 0) {
165
- resolvedLogDir = path.isAbsolute(LOG_DIR_ENV) ? LOG_DIR_ENV : path.join(getDataDir(), LOG_DIR_ENV);
166
- } else {
167
- resolvedLogDir = path.join(getDataDir(), "logs");
160
+ const logDirEnv = process.env["LOG_DIR"];
161
+ if (logDirEnv !== void 0 && logDirEnv !== "") {
162
+ return path.isAbsolute(logDirEnv) ? logDirEnv : path.join(getDataDir(), logDirEnv);
168
163
  }
169
- return resolvedLogDir;
164
+ return path.join(getDataDir(), "logs");
170
165
  }
171
166
  function getLogFilePath() {
172
167
  const date = /* @__PURE__ */ new Date();
@@ -176,8 +171,9 @@ function getLogFilePath() {
176
171
  return path.join(resolveLogDir(), `${yyyy}-${mm}-${dd}.jsonl`);
177
172
  }
178
173
  function getInspectorLogPath() {
179
- if (LOG_FILE_ENV !== void 0) {
180
- return LOG_FILE_ENV;
174
+ const logFileEnv = process.env["AGENT_INSPECTOR_LOG_FILE"];
175
+ if (logFileEnv !== void 0 && logFileEnv !== "") {
176
+ return logFileEnv;
181
177
  }
182
178
  return path.join(getDataDir(), "logs", "inspector.log");
183
179
  }
@@ -186,6 +182,7 @@ async function initLogger() {
186
182
  const retentionMs = RETENTION_DAYS * 24 * 60 * 60 * 1e3;
187
183
  const cutoff = Date.now() - retentionMs;
188
184
  try {
185
+ await mkdir(dir, { recursive: true });
189
186
  const entries = await readdir(dir);
190
187
  for (const entry of entries) {
191
188
  if (!entry.endsWith(".jsonl")) continue;
@@ -852,10 +849,10 @@ const StreamingChunksDataSchema = object({
852
849
  chunks: array(StreamingChunkSchema),
853
850
  truncated: boolean().optional()
854
851
  });
855
- const CHUNKS_DIR_ENV = process.env["CHUNKS_DIR"];
856
852
  function getChunksDir() {
857
- if (CHUNKS_DIR_ENV !== void 0) {
858
- return isAbsolute(CHUNKS_DIR_ENV) ? CHUNKS_DIR_ENV : join(getDataDir(), CHUNKS_DIR_ENV);
853
+ const chunksDirEnv = process.env["CHUNKS_DIR"];
854
+ if (chunksDirEnv !== void 0 && chunksDirEnv !== "") {
855
+ return isAbsolute(chunksDirEnv) ? chunksDirEnv : join(getDataDir(), chunksDirEnv);
859
856
  }
860
857
  return join(getDataDir(), "chunks");
861
858
  }
@@ -1228,11 +1225,6 @@ function removeFromCache(id) {
1228
1225
  }
1229
1226
  async function addTestLogEntry(entry) {
1230
1227
  const id = await getNextLogId();
1231
- const index = await loadIndex();
1232
- if (id > index.maxId) {
1233
- index.maxId = id;
1234
- await saveIndex(index);
1235
- }
1236
1228
  let streamingChunksPath = null;
1237
1229
  if (entry.streamingChunks !== void 0 && entry.streamingChunks.chunks.length > 0) {
1238
1230
  streamingChunksPath = writeChunks(
@@ -1251,6 +1243,9 @@ async function addTestLogEntry(entry) {
1251
1243
  sessionId: session.id,
1252
1244
  streamingChunksPath
1253
1245
  };
1246
+ const logFile = getCurrentLogFile();
1247
+ appendLogEntry(log);
1248
+ await addToIndex(id, logFile, -1, -1);
1254
1249
  addToCache(log);
1255
1250
  observeSessionLog(log, session.source);
1256
1251
  emitLogUpdate(log);
@@ -4729,7 +4724,7 @@ const RedactionMetadataSchema = object({
4729
4724
  redacted: boolean(),
4730
4725
  patterns: array(string())
4731
4726
  });
4732
- object({
4727
+ const KnowledgeCandidateSchema = object({
4733
4728
  id: string(),
4734
4729
  type: KnowledgeCandidateTypeSchema,
4735
4730
  title: string(),
@@ -4770,6 +4765,192 @@ const KnowledgeSearchResponseSchema = object({
4770
4765
  results: array(KnowledgeSearchResultSchema),
4771
4766
  warning: string().nullable()
4772
4767
  });
4768
+ const OpenClawGatewayErrorSchema = object({
4769
+ type: string().optional(),
4770
+ message: string().optional()
4771
+ }).passthrough();
4772
+ const OpenClawGatewayInvokeResponseSchema = object({
4773
+ ok: boolean().optional(),
4774
+ result: unknown().optional(),
4775
+ error: OpenClawGatewayErrorSchema.optional()
4776
+ }).passthrough();
4777
+ const OpenClawGatewayContentItemSchema = object({
4778
+ type: string().optional(),
4779
+ text: string().optional()
4780
+ }).passthrough();
4781
+ const OpenClawMemoryHitSchema = object({
4782
+ id: string().optional(),
4783
+ path: string().optional(),
4784
+ title: string().optional(),
4785
+ kind: string().optional(),
4786
+ corpus: string().optional(),
4787
+ score: number().nullable().optional(),
4788
+ snippet: string().optional(),
4789
+ content: string().optional(),
4790
+ source: string().nullable().optional(),
4791
+ startLine: number().optional(),
4792
+ endLine: number().optional()
4793
+ }).passthrough();
4794
+ const OpenClawToolResultDetailsSchema = object({
4795
+ results: array(OpenClawMemoryHitSchema).optional()
4796
+ }).passthrough();
4797
+ const OpenClawToolResultSchema = object({
4798
+ results: array(OpenClawMemoryHitSchema).optional(),
4799
+ details: OpenClawToolResultDetailsSchema.optional(),
4800
+ content: array(OpenClawGatewayContentItemSchema).optional()
4801
+ }).passthrough();
4802
+ function getOpenClawGatewayUrl() {
4803
+ const value = process.env["OPENCLAW_GATEWAY_URL"];
4804
+ if (value === void 0 || value.trim() === "") {
4805
+ return null;
4806
+ }
4807
+ return value.trim();
4808
+ }
4809
+ function isOpenClawGatewayConfigured() {
4810
+ return getOpenClawGatewayUrl() !== null;
4811
+ }
4812
+ function buildToolInvokeUrl(gatewayUrl) {
4813
+ return `${gatewayUrl.replace(/\/$/, "")}/tools/invoke`;
4814
+ }
4815
+ function getOpenClawSessionKey() {
4816
+ const value = process.env["OPENCLAW_SESSION_KEY"];
4817
+ return value === void 0 || value.trim() === "" ? "main" : value.trim();
4818
+ }
4819
+ function getGatewayToken() {
4820
+ const token = process.env["OPENCLAW_GATEWAY_TOKEN"] ?? process.env["OPENCLAW_GATEWAY_PASSWORD"] ?? process.env["OPENCLAW_API_KEY"];
4821
+ if (token === void 0 || token.trim() === "") {
4822
+ return null;
4823
+ }
4824
+ return token.trim();
4825
+ }
4826
+ function gatewayHeaders() {
4827
+ const headers = new Headers({ "content-type": "application/json" });
4828
+ const token = getGatewayToken();
4829
+ if (token !== null) {
4830
+ headers.set("authorization", `Bearer ${token}`);
4831
+ }
4832
+ return headers;
4833
+ }
4834
+ function buildSearchQuery(query, project) {
4835
+ if (project === void 0 || project === "") {
4836
+ return query;
4837
+ }
4838
+ return `${query}
4839
+ Project: ${project}`;
4840
+ }
4841
+ function formatHitTitle(hit, index) {
4842
+ if (hit.title !== void 0 && hit.title !== "") {
4843
+ return hit.title;
4844
+ }
4845
+ if (hit.path !== void 0 && hit.path !== "") {
4846
+ return hit.path;
4847
+ }
4848
+ if (hit.id !== void 0 && hit.id !== "") {
4849
+ return hit.id;
4850
+ }
4851
+ return `OpenClaw memory result ${String(index + 1)}`;
4852
+ }
4853
+ function formatHitId(hit, index) {
4854
+ const base = hit.id ?? hit.path ?? `result-${String(index + 1)}`;
4855
+ const start = hit.startLine === void 0 ? "" : `:${String(hit.startLine)}`;
4856
+ const end = hit.endLine === void 0 ? "" : `-${String(hit.endLine)}`;
4857
+ return `openclaw:${base}${start}${end}`;
4858
+ }
4859
+ function formatHitContent(hit) {
4860
+ if (hit.snippet !== void 0 && hit.snippet !== "") {
4861
+ return hit.snippet;
4862
+ }
4863
+ if (hit.content !== void 0 && hit.content !== "") {
4864
+ return hit.content;
4865
+ }
4866
+ return "";
4867
+ }
4868
+ function formatHitType(hit) {
4869
+ if (hit.kind !== void 0 && hit.kind !== "") {
4870
+ return hit.kind;
4871
+ }
4872
+ if (hit.corpus !== void 0 && hit.corpus !== "") {
4873
+ return hit.corpus;
4874
+ }
4875
+ return "openclaw-memory";
4876
+ }
4877
+ function mapGatewayHit(hit, index, project) {
4878
+ return {
4879
+ id: formatHitId(hit, index),
4880
+ type: formatHitType(hit),
4881
+ title: formatHitTitle(hit, index),
4882
+ content: formatHitContent(hit),
4883
+ score: hit.score ?? null,
4884
+ source: hit.source ?? "openclaw",
4885
+ project: project ?? null,
4886
+ evidence: hit
4887
+ };
4888
+ }
4889
+ function extractGatewayHits(result) {
4890
+ const parsed = OpenClawToolResultSchema.safeParse(result);
4891
+ if (!parsed.success) {
4892
+ return null;
4893
+ }
4894
+ return parsed.data.details?.results ?? parsed.data.results ?? [];
4895
+ }
4896
+ function formatGatewayError(raw) {
4897
+ const parsed = OpenClawGatewayInvokeResponseSchema.safeParse(raw);
4898
+ if (!parsed.success) {
4899
+ return "OpenClaw Gateway returned an unparseable response.";
4900
+ }
4901
+ const message = parsed.data.error?.message;
4902
+ if (message !== void 0 && message !== "") {
4903
+ return message;
4904
+ }
4905
+ return "OpenClaw Gateway tool invocation failed.";
4906
+ }
4907
+ async function searchOpenClawGateway(query, project) {
4908
+ const gatewayUrl = getOpenClawGatewayUrl();
4909
+ if (gatewayUrl === null) {
4910
+ return {
4911
+ results: [],
4912
+ warning: "OpenClaw Gateway is not configured. Set OPENCLAW_GATEWAY_URL."
4913
+ };
4914
+ }
4915
+ const response = await fetch(buildToolInvokeUrl(gatewayUrl), {
4916
+ method: "POST",
4917
+ headers: gatewayHeaders(),
4918
+ body: JSON.stringify({
4919
+ tool: "memory_search",
4920
+ args: {
4921
+ query: buildSearchQuery(query, project),
4922
+ maxResults: 10,
4923
+ corpus: "all"
4924
+ },
4925
+ sessionKey: getOpenClawSessionKey()
4926
+ })
4927
+ });
4928
+ const raw = await response.json().catch(() => null);
4929
+ if (!response.ok) {
4930
+ return {
4931
+ results: [],
4932
+ warning: `OpenClaw Gateway search failed with ${response.status}: ${formatGatewayError(raw)}`
4933
+ };
4934
+ }
4935
+ const parsed = OpenClawGatewayInvokeResponseSchema.safeParse(raw);
4936
+ if (!parsed.success) {
4937
+ return { results: [], warning: "OpenClaw Gateway returned an unparseable response." };
4938
+ }
4939
+ if (parsed.data.ok === false) {
4940
+ return { results: [], warning: formatGatewayError(raw) };
4941
+ }
4942
+ const hits = extractGatewayHits(parsed.data.result);
4943
+ if (hits === null) {
4944
+ return {
4945
+ results: [],
4946
+ warning: "OpenClaw memory_search returned an unparseable tool result."
4947
+ };
4948
+ }
4949
+ return {
4950
+ results: hits.map((hit, index) => mapGatewayHit(hit, index, project)),
4951
+ warning: null
4952
+ };
4953
+ }
4773
4954
  const REDACTION_PATTERNS = [
4774
4955
  { name: "authorization-header", pattern: /\bAuthorization\s*:\s*[^\s,;]+/gi },
4775
4956
  { name: "bearer-token", pattern: /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi },
@@ -4832,11 +5013,121 @@ function redactCandidate(candidate) {
4832
5013
  redaction: combineRedaction(patterns)
4833
5014
  };
4834
5015
  }
5016
+ function getOpenClawWorkspaceDir() {
5017
+ const value = process.env["OPENCLAW_WORKSPACE_DIR"];
5018
+ if (value === void 0 || value.trim() === "") {
5019
+ return null;
5020
+ }
5021
+ return value.trim();
5022
+ }
5023
+ function isOpenClawFileBridgeConfigured() {
5024
+ return getOpenClawWorkspaceDir() !== null;
5025
+ }
5026
+ function normalizeDatePrefix(value) {
5027
+ const date = value.slice(0, 10);
5028
+ return /^\d{4}-\d{2}-\d{2}$/.test(date) ? date : "undated";
5029
+ }
5030
+ function normalizePathSegment(value, fallback) {
5031
+ const segment = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 96);
5032
+ return segment === "" ? fallback : segment;
5033
+ }
5034
+ function formatNullable(value) {
5035
+ return value === null || value === "" ? "unknown" : value;
5036
+ }
5037
+ function formatList(values) {
5038
+ return values.length === 0 ? "none" : values.join(", ");
5039
+ }
5040
+ function buildEvidenceLink(candidate) {
5041
+ return `agent-inspector:session:${candidate.sessionId}:candidate:${candidate.id}`;
5042
+ }
5043
+ function buildOpenClawMemoryRelativePath(candidate) {
5044
+ const date = normalizeDatePrefix(candidate.updatedAt);
5045
+ const slug = normalizePathSegment(candidate.id, "candidate");
5046
+ return path.join("memory", "agent-inspector", date, `${slug}.md`).replace(/\\/g, "/");
5047
+ }
5048
+ function buildOpenClawMemoryMarkdown(candidate) {
5049
+ const sanitized = redactCandidate(candidate);
5050
+ return [
5051
+ "# Agent Inspector Memory Candidate",
5052
+ "",
5053
+ "Layer: L3 memory candidate for OpenClaw L4 durable recall",
5054
+ "Source: agent-inspector",
5055
+ "",
5056
+ "## Metadata",
5057
+ "",
5058
+ `- Type: ${sanitized.type}`,
5059
+ `- Status: ${sanitized.status}`,
5060
+ `- Project: ${formatNullable(sanitized.evidence.project)}`,
5061
+ `- Session: ${sanitized.sessionId}`,
5062
+ `- Log IDs: ${sanitized.logIds.join(", ")}`,
5063
+ `- Models: ${formatList(sanitized.evidence.models)}`,
5064
+ `- Tags: ${formatList(sanitized.tags)}`,
5065
+ `- Created: ${sanitized.createdAt}`,
5066
+ `- Updated: ${sanitized.updatedAt}`,
5067
+ `- Evidence: ${buildEvidenceLink(sanitized)}`,
5068
+ `- Redacted: ${String(sanitized.redaction.redacted)}`,
5069
+ `- Redaction patterns: ${formatList(sanitized.redaction.patterns)}`,
5070
+ "",
5071
+ "## Durable Knowledge Candidate",
5072
+ "",
5073
+ sanitized.content,
5074
+ "",
5075
+ "## Recall Guidance",
5076
+ "",
5077
+ [
5078
+ "- Treat this as reviewed Agent Inspector knowledge extracted from LLM interaction traces.",
5079
+ "- Use the evidence id to return to Agent Inspector when raw proof is needed.",
5080
+ "- Do not treat this file as raw logs; sensitive values were redacted before export."
5081
+ ].join("\n"),
5082
+ ""
5083
+ ].join("\n");
5084
+ }
5085
+ function resolveTargetPath(workspaceDir, relativePath) {
5086
+ const root = path.resolve(workspaceDir);
5087
+ const target = path.resolve(root, relativePath);
5088
+ const relative = path.relative(root, target);
5089
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
5090
+ return null;
5091
+ }
5092
+ return target;
5093
+ }
5094
+ async function writeCandidateToOpenClawMemory(candidate) {
5095
+ const workspaceDir = getOpenClawWorkspaceDir();
5096
+ if (workspaceDir === null) {
5097
+ return {
5098
+ success: false,
5099
+ error: "OpenClaw workspace is not configured. Set OPENCLAW_WORKSPACE_DIR."
5100
+ };
5101
+ }
5102
+ const relativePath = buildOpenClawMemoryRelativePath(candidate);
5103
+ const target = resolveTargetPath(workspaceDir, relativePath);
5104
+ if (target === null) {
5105
+ return {
5106
+ success: false,
5107
+ error: "OpenClaw memory target resolved outside OPENCLAW_WORKSPACE_DIR."
5108
+ };
5109
+ }
5110
+ try {
5111
+ await fs.mkdir(path.dirname(target), { recursive: true });
5112
+ await fs.writeFile(target, buildOpenClawMemoryMarkdown(candidate), "utf8");
5113
+ } catch (error) {
5114
+ return {
5115
+ success: false,
5116
+ error: `OpenClaw memory file write failed: ${String(error)}`
5117
+ };
5118
+ }
5119
+ return {
5120
+ success: true,
5121
+ memoryId: `openclaw-file:${relativePath}`,
5122
+ relativePath,
5123
+ absolutePath: target
5124
+ };
5125
+ }
4835
5126
  const OpenClawWriteResponseSchema = object({
4836
5127
  id: string().optional(),
4837
5128
  memoryId: string().optional()
4838
5129
  });
4839
- function getEndpoint() {
5130
+ function getLegacyEndpoint() {
4840
5131
  const endpoint = process.env["OPENCLAW_MEMORY_URL"] ?? process.env["OPENCLAW_API_URL"];
4841
5132
  if (endpoint === void 0 || endpoint.trim() === "") return null;
4842
5133
  return endpoint.trim();
@@ -4874,11 +5165,18 @@ function buildOpenClawPayload(candidate) {
4874
5165
  };
4875
5166
  }
4876
5167
  async function promoteToOpenClaw(candidate) {
4877
- const endpoint = getEndpoint();
5168
+ if (isOpenClawFileBridgeConfigured()) {
5169
+ const result = await writeCandidateToOpenClawMemory(candidate);
5170
+ if (result.success) {
5171
+ return { success: true, memoryId: result.memoryId };
5172
+ }
5173
+ return { success: false, error: result.error };
5174
+ }
5175
+ const endpoint = getLegacyEndpoint();
4878
5176
  if (endpoint === null) {
4879
5177
  return {
4880
5178
  success: false,
4881
- error: "OpenClaw memory backend is not configured. Set OPENCLAW_MEMORY_URL."
5179
+ error: "OpenClaw memory backend is not configured. Set OPENCLAW_WORKSPACE_DIR for file-backed memory or OPENCLAW_MEMORY_URL for a legacy HTTP backend."
4882
5180
  };
4883
5181
  }
4884
5182
  const response = await fetch(buildMemoryUrl(endpoint), {
@@ -4897,11 +5195,15 @@ async function promoteToOpenClaw(candidate) {
4897
5195
  return { success: true, memoryId: parsed.data.memoryId ?? parsed.data.id ?? null };
4898
5196
  }
4899
5197
  async function searchOpenClaw(query, project) {
4900
- const endpoint = getEndpoint();
5198
+ if (isOpenClawGatewayConfigured()) {
5199
+ return await searchOpenClawGateway(query, project);
5200
+ }
5201
+ const endpoint = getLegacyEndpoint();
4901
5202
  if (endpoint === null) {
5203
+ const workspaceHint = isOpenClawFileBridgeConfigured() ? " OPENCLAW_WORKSPACE_DIR is configured for writes, but search requires OPENCLAW_GATEWAY_URL." : "";
4902
5204
  return {
4903
5205
  results: [],
4904
- warning: "OpenClaw memory backend is not configured. Set OPENCLAW_MEMORY_URL."
5206
+ warning: `OpenClaw search backend is not configured. Set OPENCLAW_GATEWAY_URL or OPENCLAW_MEMORY_URL.${workspaceHint}`
4905
5207
  };
4906
5208
  }
4907
5209
  const response = await fetch(buildSearchUrl(endpoint, query, project), {
@@ -5028,6 +5330,62 @@ const Route$6 = createFileRoute("/api/config/paths")({
5028
5330
  }
5029
5331
  }
5030
5332
  });
5333
+ const MEMORY_PROBE_FACTS = [
5334
+ "Project fact: Agent Inspector captures LLM traffic and turns it into Raw Trace, Session Episode, and Memory Candidate layers.",
5335
+ "Procedure: before release, run bun test, npm run typecheck, npm run lint, npm run build, and openspec validate --all --strict.",
5336
+ "Preference: the user prefers Chinese summaries, explicit verification, and commit/push/release closure when requested.",
5337
+ "Pitfall: preserve .llm-inspector config compatibility; do not write raw logs or secrets into durable memory.",
5338
+ "OpenClaw boundary: Agent Inspector owns L1-L3; OpenClaw owns durable indexing, retrieval, and recall."
5339
+ ];
5340
+ function modeInstruction(mode) {
5341
+ switch (mode) {
5342
+ case "non-streaming":
5343
+ return "Reply in four concise bullets.";
5344
+ case "streaming":
5345
+ return "Reply in three concise bullets.";
5346
+ }
5347
+ }
5348
+ function maxTokensForMode(mode) {
5349
+ switch (mode) {
5350
+ case "non-streaming":
5351
+ return 1024;
5352
+ case "streaming":
5353
+ return 384;
5354
+ }
5355
+ }
5356
+ function buildProviderTestUserPrompt(mode) {
5357
+ return [
5358
+ "You are validating an LLM provider connection for Agent Inspector.",
5359
+ "This request includes a synthetic memory probe so Agent Inspector can verify its three Inspector-owned memory layers.",
5360
+ "",
5361
+ "Synthetic memory probe:",
5362
+ ...MEMORY_PROBE_FACTS.map((fact) => `- ${fact}`),
5363
+ "",
5364
+ "Return:",
5365
+ "1. connection status",
5366
+ "2. one project fact",
5367
+ "3. one reusable procedure",
5368
+ "4. one caution",
5369
+ "",
5370
+ modeInstruction(mode)
5371
+ ].join("\n");
5372
+ }
5373
+ function buildProviderTestMessages(mode) {
5374
+ return [{ role: "user", content: buildProviderTestUserPrompt(mode) }];
5375
+ }
5376
+ function buildProviderTestRequestBody(model, mode) {
5377
+ const base = {
5378
+ model,
5379
+ messages: buildProviderTestMessages(mode),
5380
+ max_tokens: maxTokensForMode(mode)
5381
+ };
5382
+ switch (mode) {
5383
+ case "non-streaming":
5384
+ return base;
5385
+ case "streaming":
5386
+ return { ...base, stream: true };
5387
+ }
5388
+ }
5031
5389
  const ERROR_HINTS = {
5032
5390
  timeout: "The request took too long. Check your network connection or try again.",
5033
5391
  network_unreachable: "Cannot reach the server. Verify the base URL and check your firewall settings.",
@@ -5193,11 +5551,7 @@ function buildTestRequestHeaders(provider) {
5193
5551
  }
5194
5552
  async function testEndpoint(baseUrl, provider, path2, model, isOpenAI) {
5195
5553
  const startTime = Date.now();
5196
- const body = JSON.stringify({
5197
- model,
5198
- messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
5199
- max_tokens: 1024
5200
- });
5554
+ const body = JSON.stringify(buildProviderTestRequestBody(model, "non-streaming"));
5201
5555
  const requestHeaders = buildTestRequestHeaders(provider);
5202
5556
  const controller = new AbortController();
5203
5557
  const timeoutId = setTimeout(() => controller.abort(), TEST_TIMEOUT_MS);
@@ -5282,12 +5636,7 @@ async function testEndpoint(baseUrl, provider, path2, model, isOpenAI) {
5282
5636
  }
5283
5637
  async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI) {
5284
5638
  const startTime = Date.now();
5285
- const body = JSON.stringify({
5286
- model,
5287
- messages: [{ role: "user", content: "say hello" }],
5288
- max_tokens: 256,
5289
- stream: true
5290
- });
5639
+ const body = JSON.stringify(buildProviderTestRequestBody(model, "streaming"));
5291
5640
  const requestHeaders = buildTestRequestHeaders(provider);
5292
5641
  const controller = new AbortController();
5293
5642
  const timeoutId = setTimeout(() => controller.abort(), TEST_TIMEOUT_MS);
@@ -5743,30 +6092,6 @@ function createFailedProviderTestResults(message, type) {
5743
6092
  function hasSuccessField(result) {
5744
6093
  return Object.prototype.hasOwnProperty.call(result, "success");
5745
6094
  }
5746
- function createTestLogEntry(providerName, path2, body, upstreamUrl, result, isTest) {
5747
- return {
5748
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5749
- id: `test-${Date.now()}`,
5750
- method: "POST",
5751
- path: path2,
5752
- model: isTest ? result.model : void 0,
5753
- sessionId: null,
5754
- rawRequestBody: body,
5755
- responseStatus: result.success ? 200 : 500,
5756
- responseText: result.rawResponse ?? JSON.stringify(result),
5757
- inputTokens: result.inputTokens ?? null,
5758
- outputTokens: result.outputTokens ?? null,
5759
- elapsedMs: result.latencyMs ?? 0,
5760
- streaming: result.streaming ?? false,
5761
- userAgent: "provider-test",
5762
- origin: null,
5763
- upstreamUrl,
5764
- error: result.success ? null : result.error?.message ?? String(result.error),
5765
- isTest: true,
5766
- providerName,
5767
- headers: result.requestHeaders ?? {}
5768
- };
5769
- }
5770
6095
  async function logModelResults(displayName, providerName, anthropicUrl, openaiUrl, modelResults) {
5771
6096
  const usageModel = getModelUsageName(displayName, providerName);
5772
6097
  if (anthropicUrl !== void 0) {
@@ -5775,12 +6100,7 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
5775
6100
  if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
5776
6101
  const nonStreamingResult = nsResult;
5777
6102
  const streamingResult = sResult;
5778
- const requestBody = JSON.stringify({
5779
- model: usageModel,
5780
- messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
5781
- max_tokens: 1024
5782
- });
5783
- const upstreamUrl = `${anthropicUrl}/v1/messages`;
6103
+ const requestBody = JSON.stringify(buildProviderTestRequestBody(usageModel, "non-streaming"));
5784
6104
  await addTestLogEntry({
5785
6105
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5786
6106
  method: "POST",
@@ -5803,22 +6123,9 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
5803
6123
  providerName,
5804
6124
  headers: nonStreamingResult.requestHeaders ?? {}
5805
6125
  });
5806
- appendLogEntry(
5807
- createTestLogEntry(
5808
- providerName,
5809
- "/v1/messages",
5810
- requestBody,
5811
- upstreamUrl,
5812
- nonStreamingResult,
5813
- true
5814
- )
6126
+ const streamingRequestBody = JSON.stringify(
6127
+ buildProviderTestRequestBody(usageModel, "streaming")
5815
6128
  );
5816
- const streamingRequestBody = JSON.stringify({
5817
- model: usageModel,
5818
- messages: [{ role: "user", content: "say hello" }],
5819
- max_tokens: 256,
5820
- stream: true
5821
- });
5822
6129
  await addTestLogEntry({
5823
6130
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5824
6131
  method: "POST",
@@ -5842,16 +6149,6 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
5842
6149
  providerName,
5843
6150
  headers: streamingResult.requestHeaders ?? {}
5844
6151
  });
5845
- appendLogEntry(
5846
- createTestLogEntry(
5847
- providerName,
5848
- "/v1/messages",
5849
- streamingRequestBody,
5850
- upstreamUrl,
5851
- streamingResult,
5852
- true
5853
- )
5854
- );
5855
6152
  }
5856
6153
  }
5857
6154
  if (openaiUrl !== void 0) {
@@ -5860,12 +6157,7 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
5860
6157
  if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
5861
6158
  const nonStreamingResult = nsResult;
5862
6159
  const streamingResult = sResult;
5863
- const requestBody = JSON.stringify({
5864
- model: usageModel,
5865
- messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
5866
- max_tokens: 1024
5867
- });
5868
- const upstreamUrl = `${openaiUrl}/v1/chat/completions`;
6160
+ const requestBody = JSON.stringify(buildProviderTestRequestBody(usageModel, "non-streaming"));
5869
6161
  await addTestLogEntry({
5870
6162
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5871
6163
  method: "POST",
@@ -5888,22 +6180,9 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
5888
6180
  providerName,
5889
6181
  headers: nonStreamingResult.requestHeaders ?? {}
5890
6182
  });
5891
- appendLogEntry(
5892
- createTestLogEntry(
5893
- providerName,
5894
- "/v1/chat/completions",
5895
- requestBody,
5896
- upstreamUrl,
5897
- nonStreamingResult,
5898
- true
5899
- )
6183
+ const streamingRequestBody = JSON.stringify(
6184
+ buildProviderTestRequestBody(usageModel, "streaming")
5900
6185
  );
5901
- const streamingRequestBody = JSON.stringify({
5902
- model: usageModel,
5903
- messages: [{ role: "user", content: "say hello" }],
5904
- max_tokens: 256,
5905
- stream: true
5906
- });
5907
6186
  await addTestLogEntry({
5908
6187
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5909
6188
  method: "POST",
@@ -5927,16 +6206,6 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
5927
6206
  providerName,
5928
6207
  headers: streamingResult.requestHeaders ?? {}
5929
6208
  });
5930
- appendLogEntry(
5931
- createTestLogEntry(
5932
- providerName,
5933
- "/v1/chat/completions",
5934
- streamingRequestBody,
5935
- upstreamUrl,
5936
- streamingResult,
5937
- true
5938
- )
5939
- );
5940
6209
  }
5941
6210
  }
5942
6211
  }
@@ -6300,17 +6569,19 @@ export {
6300
6569
  AnthropicResponseSchema$1 as A,
6301
6570
  CapturedLogSchema as C,
6302
6571
  DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as D,
6572
+ KnowledgeCandidateSchema as K,
6303
6573
  MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as M,
6304
6574
  OpenAIRequestSchema as O,
6305
6575
  ProviderTestResultsSchema as P,
6306
6576
  Route$o as R,
6307
6577
  RuntimeConfigSchema as a,
6308
6578
  AnthropicRequestSchema as b,
6309
- createPendingProviderTestResults as c,
6310
- createFailedProviderTestResults as d,
6311
- ProviderConfigSchema as e,
6312
- router as f,
6579
+ safeGetOwnProperty as c,
6580
+ createPendingProviderTestResults as d,
6581
+ createFailedProviderTestResults as e,
6582
+ ProviderConfigSchema as f,
6313
6583
  getSessionPath as g,
6584
+ router as h,
6314
6585
  parseOpenAIResponse as p,
6315
6586
  requestFormatForPath as r,
6316
6587
  stripClaudeCodeBillingHeader as s