@tomflow/proflow-agent-gateway 0.1.17 → 0.1.18

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @tomflow/proflow-agent-gateway
2
2
 
3
+ ## 0.1.18
4
+
5
+ ### Patch Changes
6
+
7
+ - Aggregate Browser, Permission, Host-application, Provisioning, Direct Tool, and Gateway observability at stable runtime boundaries, preserving owner truth while enabling one operation-chain diagnosis path without logging sensitive payloads.
8
+
3
9
  ## 0.1.17
4
10
 
5
11
  ### Patch Changes
@@ -6,7 +6,7 @@ export declare const behaviorAdapter: {
6
6
  ok: true;
7
7
  status: "SUCCEEDED";
8
8
  moduleRef: "agent-gateway";
9
- moduleVersion: "0.1.17";
9
+ moduleVersion: "0.1.18";
10
10
  data: {
11
11
  localBaseUrl: string;
12
12
  publicBaseUrl?: string;
@@ -20,7 +20,7 @@ export declare const behaviorAdapter: {
20
20
  readonly ok: true;
21
21
  readonly status: "SUCCEEDED";
22
22
  readonly moduleRef: "agent-gateway";
23
- readonly moduleVersion: "0.1.17";
23
+ readonly moduleVersion: "0.1.18";
24
24
  };
25
25
  observedEffects: string[];
26
26
  }>;
@@ -30,7 +30,7 @@ export declare const behaviorAdapter: {
30
30
  ok: true;
31
31
  status: "SUCCEEDED";
32
32
  moduleRef: "agent-gateway";
33
- moduleVersion: "0.1.17";
33
+ moduleVersion: "0.1.18";
34
34
  data: {
35
35
  setupStatus: "BLOCKED" | "READY";
36
36
  runtimeStatus: "RUNNING" | "STOPPED";
@@ -51,7 +51,7 @@ export declare const behaviorAdapter: {
51
51
  ok: true;
52
52
  status: "SUCCEEDED";
53
53
  moduleRef: "agent-gateway";
54
- moduleVersion: "0.1.17";
54
+ moduleVersion: "0.1.18";
55
55
  data: {
56
56
  localBaseUrl: string;
57
57
  publicBaseUrl?: string;
@@ -66,7 +66,7 @@ export declare const behaviorAdapter: {
66
66
  ok: true;
67
67
  status: "SUCCEEDED";
68
68
  moduleRef: "agent-gateway";
69
- moduleVersion: "0.1.17";
69
+ moduleVersion: "0.1.18";
70
70
  data: {
71
71
  docs: string;
72
72
  };
@@ -79,7 +79,7 @@ export declare const behaviorAdapter: {
79
79
  ok: true;
80
80
  status: "SUCCEEDED";
81
81
  moduleRef: "agent-gateway";
82
- moduleVersion: "0.1.17";
82
+ moduleVersion: "0.1.18";
83
83
  data: {
84
84
  host: string;
85
85
  port: number;
@@ -90,7 +90,7 @@ export declare const behaviorAdapter: {
90
90
  result: {
91
91
  contract: "deployment.result.v1";
92
92
  moduleRef: "agent-gateway";
93
- moduleVersion: "0.1.17";
93
+ moduleVersion: "0.1.18";
94
94
  ok: false;
95
95
  status: "FAILED";
96
96
  error: {
@@ -107,7 +107,7 @@ export declare const behaviorAdapter: {
107
107
  readonly ok: true;
108
108
  readonly status: "SUCCEEDED";
109
109
  readonly moduleRef: "agent-gateway";
110
- readonly moduleVersion: "0.1.17";
110
+ readonly moduleVersion: "0.1.18";
111
111
  };
112
112
  observedEffects: string[];
113
113
  } | {
@@ -116,11 +116,11 @@ export declare const behaviorAdapter: {
116
116
  readonly ok: true;
117
117
  readonly status: "SUCCEEDED";
118
118
  readonly moduleRef: "agent-gateway";
119
- readonly moduleVersion: "0.1.17";
119
+ readonly moduleVersion: "0.1.18";
120
120
  } | {
121
121
  contract: "deployment.result.v1";
122
122
  moduleRef: "agent-gateway";
123
- moduleVersion: "0.1.17";
123
+ moduleVersion: "0.1.18";
124
124
  ok: false;
125
125
  status: "FAILED";
126
126
  error: {
@@ -1,5 +1,6 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
- import { join, resolve } from "node:path";
2
+ import { appendFile, mkdir } from "node:fs/promises";
3
+ import { dirname, join, resolve } from "node:path";
3
4
  import { deterministicLoopbackPort, readModuleSharedFacts, writeModuleSharedFacts, } from "@tomflow/proflow-module-contract";
4
5
  import { descriptor } from "./descriptor.js";
5
6
  const services = new Map();
@@ -72,6 +73,20 @@ async function compose(context) {
72
73
  const credentialFile = join(deps.stateRoot, "agent", "secrets", "role-credentials.json");
73
74
  if (!existsSync(credentialFile))
74
75
  throw new Error("Agent role credential store is not materialized by Platform Host");
76
+ const logPath = join(deps.stateRoot, "logs", "agent-gateway", "events.jsonl");
77
+ let logTail = Promise.resolve();
78
+ const log = (entry) => {
79
+ logTail = logTail
80
+ .catch(() => undefined)
81
+ .then(async () => {
82
+ await mkdir(dirname(logPath), { recursive: true, mode: 0o700 });
83
+ await appendFile(logPath, `${JSON.stringify(entry)}\n`, {
84
+ encoding: "utf8",
85
+ mode: 0o600,
86
+ });
87
+ });
88
+ void logTail;
89
+ };
75
90
  const { createAgentGatewayProcess, parseAgentGatewayProcessConfig } = await import("../src/process.js");
76
91
  const listener = new URL(own.localBaseUrl);
77
92
  return createAgentGatewayProcess({
@@ -83,6 +98,8 @@ async function compose(context) {
83
98
  credentialFile,
84
99
  downstreamCredentialFile: deps.downstreamCredentialFile,
85
100
  }),
101
+ log,
102
+ operationLog: log,
86
103
  });
87
104
  }
88
105
  const failed = (code, message) => ({
@@ -104,7 +121,9 @@ export const behaviorAdapter = {
104
121
  }
105
122
  return {
106
123
  result: base,
107
- observedEffects: service ? ["Manage the declared service process"] : [],
124
+ observedEffects: service
125
+ ? ["Manage the declared service process"]
126
+ : [],
108
127
  };
109
128
  },
110
129
  status: async (context) => {
@@ -157,7 +176,9 @@ export const behaviorAdapter = {
157
176
  result: {
158
177
  ...base,
159
178
  data: {
160
- docs: readFileSync(new URL(import.meta.url.includes("/dist/") ? "../../DOCS.md" : "../DOCS.md", import.meta.url), "utf8"),
179
+ docs: readFileSync(new URL(import.meta.url.includes("/dist/")
180
+ ? "../../DOCS.md"
181
+ : "../DOCS.md", import.meta.url), "utf8"),
161
182
  },
162
183
  },
163
184
  observedEffects: [],
@@ -175,7 +196,9 @@ export const behaviorAdapter = {
175
196
  }
176
197
  catch (error) {
177
198
  return {
178
- result: failed("START_FAILED", error instanceof Error ? error.message : "agent-gateway start failed"),
199
+ result: failed("START_FAILED", error instanceof Error
200
+ ? error.message
201
+ : "agent-gateway start failed"),
179
202
  observedEffects: [],
180
203
  };
181
204
  }
@@ -3,7 +3,7 @@ export declare const descriptor: {
3
3
  readonly contractVersion: "1.0.0";
4
4
  readonly moduleRef: "agent-gateway";
5
5
  readonly packageName: "@tomflow/proflow-agent-gateway";
6
- readonly moduleVersion: "0.1.17";
6
+ readonly moduleVersion: "0.1.18";
7
7
  readonly kind: "service";
8
8
  readonly templateVersion: "1.0.0";
9
9
  readonly platformCompatibility: ">=1.0.0 <2.0.0";
@@ -3,7 +3,7 @@ export const descriptor = {
3
3
  contractVersion: "1.0.0",
4
4
  moduleRef: "agent-gateway",
5
5
  packageName: "@tomflow/proflow-agent-gateway",
6
- moduleVersion: "0.1.17",
6
+ moduleVersion: "0.1.18",
7
7
  kind: "service",
8
8
  templateVersion: "1.0.0",
9
9
  platformCompatibility: ">=1.0.0 <2.0.0",
@@ -12,6 +12,7 @@ export declare function createAgentGatewayProcess(input: {
12
12
  config: AgentGatewayProcessConfig;
13
13
  fetch?: typeof globalThis.fetch;
14
14
  log?: (entry: Record<string, unknown>) => void;
15
+ operationLog?: (entry: Record<string, unknown>) => void;
15
16
  }): Promise<Readonly<{
16
17
  readiness: () => Promise<{
17
18
  status: "NOT_READY" | "READY";
@@ -31,6 +31,7 @@ const safeDownstreamErrorCodes = new Set([
31
31
  "LOCAL_TOOL_SCOPE_DENIED",
32
32
  "LOCAL_TOOL_COMMAND_FAILED",
33
33
  ]);
34
+ const directToolOperationIds = new Set(["localDev", "repomix", "codeGraph"]);
34
35
  async function boundedDownstreamErrorCode(response) {
35
36
  if (!response.body)
36
37
  return null;
@@ -82,6 +83,27 @@ function text(value, name) {
82
83
  throw new TypeError(`${name} must be a non-empty string`);
83
84
  return value;
84
85
  }
86
+ function logErrorCode(error) {
87
+ const value = error instanceof AgentGatewayError
88
+ ? error.code
89
+ : error &&
90
+ typeof error === "object" &&
91
+ typeof Reflect.get(error, "message") === "string"
92
+ ? String(Reflect.get(error, "message"))
93
+ : "GATEWAY_FAILURE";
94
+ return /^[A-Z][A-Z0-9_.:-]{0,159}$/.test(value)
95
+ ? value
96
+ : "GATEWAY_FAILURE";
97
+ }
98
+ function optionalToolOperation(value) {
99
+ if (typeof value !== "object" ||
100
+ value === null ||
101
+ Array.isArray(value) ||
102
+ typeof Reflect.get(value, "operation") !== "string")
103
+ return undefined;
104
+ const operation = String(Reflect.get(value, "operation"));
105
+ return /^[A-Za-z0-9_.:-]{1,160}$/.test(operation) ? operation : undefined;
106
+ }
85
107
  export function parseAgentGatewayProcessConfig(value) {
86
108
  const input = record(value, "agent-gateway config");
87
109
  const publicBaseUrl = new URL(text(input.publicBaseUrl, "publicBaseUrl"));
@@ -142,11 +164,6 @@ async function readDownstreamCredential(file) {
142
164
  export async function createAgentGatewayProcess(input) {
143
165
  const fetchImplementation = input.fetch ?? globalThis.fetch;
144
166
  const credentialFile = input.config.credentialFile;
145
- // Fail-fast at startup so a malformed configured credential store is rejected
146
- // before the process advertises readiness. Authentication re-reads the current
147
- // store on every attempt below, so a rotated key takes effect without a restart
148
- // and a malformed/half-written store fails closed instead of serving a stale
149
- // snapshot.
150
167
  await readCurrentCredentialStore(credentialFile);
151
168
  if (input.config.downstreamCredentialFile)
152
169
  await readDownstreamCredential(input.config.downstreamCredentialFile);
@@ -199,6 +216,29 @@ export async function createAgentGatewayProcess(input) {
199
216
  }
200
217
  return response.json();
201
218
  };
219
+ const emitOperation = (inputEvent) => {
220
+ const toolOperation = directToolOperationIds.has(inputEvent.operationId)
221
+ ? optionalToolOperation(inputEvent.value)
222
+ : undefined;
223
+ input.operationLog?.({
224
+ contract: "proflow.operation-boundary.v1",
225
+ timestamp: new Date().toISOString(),
226
+ source: "agent-gateway",
227
+ component: "agent-gateway-ingress",
228
+ event: inputEvent.mode === "LOOKUP"
229
+ ? "GATEWAY_ACTION_LOOKUP"
230
+ : "GATEWAY_ACTION",
231
+ boundary: directToolOperationIds.has(inputEvent.operationId)
232
+ ? "TOOL_INVOCATION"
233
+ : "ACTION",
234
+ status: inputEvent.status,
235
+ operationId: inputEvent.operationId,
236
+ roleRef: inputEvent.roleRef,
237
+ ...(toolOperation ? { toolOperation } : {}),
238
+ ...(inputEvent.errorCode ? { errorCode: inputEvent.errorCode } : {}),
239
+ durationMs: inputEvent.durationMs,
240
+ });
241
+ };
202
242
  const gateway = await createAgentGateway({
203
243
  host: input.config.host,
204
244
  port: input.config.port,
@@ -211,23 +251,68 @@ export async function createAgentGatewayProcess(input) {
211
251
  return roleRef;
212
252
  throw new Error("AUTHENTICATION_FAILED");
213
253
  },
214
- route(operationId, authenticatedRoleRef, value, context) {
215
- return downstream(`/actions/${encodeURIComponent(operationId)}`, {
216
- authenticatedRoleRef,
217
- input: value,
218
- deadlineAt: context?.deadlineAt,
219
- ...(context?.fileMaterializationInputs === undefined
220
- ? {}
221
- : {
222
- fileMaterializationInputs: context.fileMaterializationInputs,
223
- }),
224
- }, context?.signal);
254
+ async route(operationId, authenticatedRoleRef, value, context) {
255
+ const started = performance.now();
256
+ try {
257
+ const result = await downstream(`/actions/${encodeURIComponent(operationId)}`, {
258
+ authenticatedRoleRef,
259
+ input: value,
260
+ deadlineAt: context?.deadlineAt,
261
+ ...(context?.fileMaterializationInputs === undefined
262
+ ? {}
263
+ : {
264
+ fileMaterializationInputs: context.fileMaterializationInputs,
265
+ }),
266
+ }, context?.signal);
267
+ emitOperation({
268
+ mode: "ROUTE",
269
+ operationId,
270
+ roleRef: authenticatedRoleRef,
271
+ value,
272
+ status: "SUCCEEDED",
273
+ durationMs: performance.now() - started,
274
+ });
275
+ return result;
276
+ }
277
+ catch (error) {
278
+ emitOperation({
279
+ mode: "ROUTE",
280
+ operationId,
281
+ roleRef: authenticatedRoleRef,
282
+ value,
283
+ status: "FAILED",
284
+ errorCode: logErrorCode(error),
285
+ durationMs: performance.now() - started,
286
+ });
287
+ throw error;
288
+ }
225
289
  },
226
- lookupResult(operationId, authenticatedRoleRef, value) {
227
- return downstream(`/actions/${encodeURIComponent(operationId)}/result`, {
228
- authenticatedRoleRef,
229
- input: value,
230
- });
290
+ async lookupResult(operationId, authenticatedRoleRef, value) {
291
+ const started = performance.now();
292
+ try {
293
+ const result = await downstream(`/actions/${encodeURIComponent(operationId)}/result`, { authenticatedRoleRef, input: value });
294
+ emitOperation({
295
+ mode: "LOOKUP",
296
+ operationId,
297
+ roleRef: authenticatedRoleRef,
298
+ value,
299
+ status: "SUCCEEDED",
300
+ durationMs: performance.now() - started,
301
+ });
302
+ return result;
303
+ }
304
+ catch (error) {
305
+ emitOperation({
306
+ mode: "LOOKUP",
307
+ operationId,
308
+ roleRef: authenticatedRoleRef,
309
+ value,
310
+ status: "FAILED",
311
+ errorCode: logErrorCode(error),
312
+ durationMs: performance.now() - started,
313
+ });
314
+ throw error;
315
+ }
231
316
  },
232
317
  async readiness() {
233
318
  try {
@@ -260,6 +345,7 @@ export async function createAgentGatewayProcess(input) {
260
345
  timestamp: new Date().toISOString(),
261
346
  component: "agent-gateway-process",
262
347
  event: "SERVICE_STARTED",
348
+ status: "SUCCEEDED",
263
349
  ...address,
264
350
  });
265
351
  return address;
@@ -270,6 +356,7 @@ export async function createAgentGatewayProcess(input) {
270
356
  timestamp: new Date().toISOString(),
271
357
  component: "agent-gateway-process",
272
358
  event: "SERVICE_STOPPED",
359
+ status: "SUCCEEDED",
273
360
  });
274
361
  };
275
362
  return Object.freeze({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomflow/proflow-agent-gateway",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -28,13 +28,13 @@
28
28
  "@tomflow/proflow-module-contract": "^0.1.13"
29
29
  },
30
30
  "devDependencies": {
31
- "@tomflow/proflow-execution-browser-extension": "^0.1.51",
32
- "@tomflow/proflow-deployment-conformance": "^0.1.13",
31
+ "@tomflow/proflow-agent-runtime": "^0.1.17",
32
+ "@tomflow/proflow-execution-browser-extension": "^0.1.58",
33
33
  "@tomflow/proflow-execution-runtime": "^0.1.19",
34
- "@tomflow/proflow-agent-runtime": "^0.1.14",
35
- "@tomflow/proflow-platform-host": "^0.1.23",
36
- "@tomflow/proflow-task-orchestration": "^0.1.11",
34
+ "@tomflow/proflow-platform-host": "^0.1.28",
35
+ "@tomflow/proflow-deployment-conformance": "^0.1.13",
37
36
  "@tomflow/proflow-task-migration-runner": "^0.1.11",
37
+ "@tomflow/proflow-task-orchestration": "^0.1.11",
38
38
  "@tomflow/proflow-task-store-sqlite": "^0.1.12"
39
39
  },
40
40
  "description": "The sole Custom GPT Actions HTTP ingress and OpenAI transport anti-corruption layer.",
@@ -3,7 +3,7 @@
3
3
  "contractVersion": "1.0.0",
4
4
  "moduleRef": "agent-gateway",
5
5
  "packageName": "@tomflow/proflow-agent-gateway",
6
- "moduleVersion": "0.1.17",
6
+ "moduleVersion": "0.1.18",
7
7
  "kind": "service",
8
8
  "templateVersion": "1.0.0",
9
9
  "platformCompatibility": ">=1.0.0 <2.0.0",