@tomflow/proflow-agent-gateway 0.1.4 → 0.1.6

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/DOCS.md ADDED
@@ -0,0 +1,29 @@
1
+ # @tomflow/proflow-agent-gateway — Module Docs
2
+
3
+ Module ref: `agent-gateway`
4
+ Domain: `agent-runtime-collaboration`
5
+ Kind: `service`
6
+
7
+ The sole Custom GPT Actions HTTP ingress and OpenAI transport anti-corruption layer.
8
+
9
+ ## Standard management surface
10
+
11
+ `install / uninstall / status / setup / docs / start / stop`
12
+
13
+ ## Provides
14
+
15
+ - `custom-gpt-actions-gateway` `1.0.0`
16
+
17
+ ## Requires
18
+
19
+ - `agent-runtime` `>=1.0.0 <2.0.0`
20
+ - `task-orchestration` `>=1.0.0 <2.0.0`
21
+ - `execution` `>=1.0.0 <2.0.0`
22
+
23
+ ## Public setup inputs
24
+
25
+ - None. Deterministic/private values and cross-Module shared facts are not public configuration.
26
+
27
+ ## Ownership boundary
28
+
29
+ Module business APIs and any module-specific extra commands remain package-owned. Platform does not proxy or interpret them. Current human/external preparation is documented in `SETUP.md`.
package/SETUP.md ADDED
@@ -0,0 +1,7 @@
1
+ # @tomflow/proflow-agent-gateway — Module Setup
2
+
3
+ No user or external setup is required by the current frozen Module contract. `Module.install` completes deterministic preparation; `Module.setup` only re-observes current reality and must not ask the user to supply private paths, loopback endpoints, tokens or cross-Module facts.
4
+
5
+ ## Completion
6
+
7
+ Setup is complete only when the Module's own `status` reports `setupStatus=READY`. Re-running setup must re-observe reality; it must not resume from a blind historical step index.
@@ -1,364 +1,134 @@
1
- type GatewayProcess = {
2
- start(): Promise<{
3
- host: string;
4
- port: number;
5
- }>;
6
- stop(): Promise<void>;
7
- restart(): Promise<{
8
- host: string;
9
- port: number;
10
- }>;
11
- readiness(): Promise<{
12
- status: "READY" | "NOT_READY";
13
- }>;
14
- status(): unknown;
15
- };
16
- export declare function createBehaviorAdapter(service?: GatewayProcess, config?: Record<string, string>, configValid?: boolean): {
17
- describe: () => {
18
- result: {
19
- readonly contract: "deployment.result.v1";
20
- readonly ok: true;
21
- readonly status: "SUCCEEDED";
22
- readonly moduleRef: "agent-gateway";
23
- readonly moduleVersion: "0.1.4";
24
- };
25
- observedEffects: never[];
26
- };
27
- preflight: () => {
28
- result: {
29
- readonly contract: "deployment.result.v1";
30
- readonly ok: true;
31
- readonly status: "SUCCEEDED";
32
- readonly moduleRef: "agent-gateway";
33
- readonly moduleVersion: "0.1.4";
34
- };
35
- observedEffects: never[];
36
- };
37
- status: () => Promise<{
1
+ import { type ModuleCommandContext } from "@tomflow/proflow-module-contract";
2
+ export declare const behaviorAdapter: {
3
+ readonly install: (context: ModuleCommandContext) => Promise<{
38
4
  result: {
39
5
  contract: "deployment.result.v1";
40
6
  ok: true;
41
7
  status: "SUCCEEDED";
42
8
  moduleRef: "agent-gateway";
43
- moduleVersion: "0.1.4";
9
+ moduleVersion: "0.1.6";
44
10
  data: {
45
- configStatus: "INCOMPLETE" | "INVALID" | "READY";
46
- missingConfig?: string[] | undefined;
47
- runtimeStatus: "FAILED" | "RUNNING" | "STOPPED" | "UNKNOWN";
11
+ localBaseUrl: string;
12
+ publicBaseUrl?: string;
48
13
  };
49
14
  };
50
15
  observedEffects: never[];
51
16
  }>;
52
- verify: () => Promise<{
53
- result: {
54
- contract: "deployment.result.v1";
55
- ok: true;
56
- status: "SUCCEEDED";
57
- moduleRef: "agent-gateway";
58
- moduleVersion: "0.1.4";
59
- checks: {
60
- id: string;
61
- status: "FAIL" | "PASS";
62
- message: string;
63
- }[];
64
- } | {
65
- contract: "deployment.result.v1";
66
- moduleRef: "agent-gateway";
67
- moduleVersion: "0.1.4";
68
- ok: false;
69
- status: "ACTION_REQUIRED";
70
- actionRequired: {
71
- readonly action: "compose-gateway";
72
- readonly description: "Provide owner ports and process configuration";
73
- };
74
- checks: {
75
- id: string;
76
- status: "FAIL" | "PASS";
77
- message: string;
78
- }[];
79
- } | {
80
- contract: "deployment.result.v1";
81
- moduleRef: "agent-gateway";
82
- moduleVersion: "0.1.4";
83
- ok: false;
84
- status: "ACTION_REQUIRED";
85
- actionRequired: {
86
- action: string;
87
- description: string;
88
- };
89
- checks: {
90
- id: string;
91
- status: "FAIL" | "PASS";
92
- message: string;
93
- }[];
94
- };
95
- observedEffects: never[];
96
- }>;
97
- doctor: () => {
98
- result: {
99
- readonly contract: "deployment.result.v1";
100
- readonly ok: true;
101
- readonly status: "SUCCEEDED";
102
- readonly moduleRef: "agent-gateway";
103
- readonly moduleVersion: "0.1.4";
104
- };
105
- observedEffects: never[];
106
- };
107
- start: () => Promise<{
108
- result: {
109
- contract: "deployment.result.v1";
110
- ok: true;
111
- status: "SUCCEEDED";
112
- moduleRef: "agent-gateway";
113
- moduleVersion: "0.1.4";
114
- data: {
115
- host: string;
116
- port: number;
117
- };
118
- } | {
119
- contract: "deployment.result.v1";
120
- moduleRef: "agent-gateway";
121
- moduleVersion: "0.1.4";
122
- status: "ACTION_REQUIRED";
123
- ok: boolean;
124
- actionRequired: {
125
- action: string;
126
- description: string;
127
- };
128
- };
129
- observedEffects: string[];
130
- }>;
131
- stop: () => Promise<{
132
- result: {
133
- readonly contract: "deployment.result.v1";
134
- readonly ok: true;
135
- readonly status: "SUCCEEDED";
136
- readonly moduleRef: "agent-gateway";
137
- readonly moduleVersion: "0.1.4";
138
- } | {
139
- readonly contract: "deployment.result.v1";
140
- readonly moduleRef: "agent-gateway";
141
- readonly moduleVersion: "0.1.4";
142
- readonly ok: false;
143
- readonly status: "ACTION_REQUIRED";
144
- readonly actionRequired: {
145
- readonly action: "compose-gateway";
146
- readonly description: "Provide owner ports and process configuration";
147
- };
148
- };
149
- observedEffects: string[];
150
- }>;
151
- uninstall: () => Promise<{
17
+ readonly uninstall: (context: ModuleCommandContext) => Promise<{
152
18
  result: {
153
19
  readonly contract: "deployment.result.v1";
154
20
  readonly ok: true;
155
21
  readonly status: "SUCCEEDED";
156
22
  readonly moduleRef: "agent-gateway";
157
- readonly moduleVersion: "0.1.4";
23
+ readonly moduleVersion: "0.1.6";
158
24
  };
159
25
  observedEffects: string[];
160
26
  }>;
161
- restart: () => Promise<{
27
+ readonly status: (context: ModuleCommandContext) => Promise<{
162
28
  result: {
163
29
  contract: "deployment.result.v1";
164
30
  ok: true;
165
31
  status: "SUCCEEDED";
166
32
  moduleRef: "agent-gateway";
167
- moduleVersion: "0.1.4";
33
+ moduleVersion: "0.1.6";
168
34
  data: {
169
- host: string;
170
- port: number;
171
- };
172
- } | {
173
- contract: "deployment.result.v1";
174
- moduleRef: "agent-gateway";
175
- moduleVersion: "0.1.4";
176
- status: "ACTION_REQUIRED";
177
- ok: boolean;
178
- actionRequired: {
179
- action: string;
180
- description: string;
35
+ setupStatus: "FAILED" | "READY";
36
+ runtimeStatus: "RUNNING" | "STOPPED";
181
37
  };
182
38
  };
183
- observedEffects: string[];
184
- }>;
185
- };
186
- export declare const behaviorAdapter: {
187
- describe: () => {
188
- result: {
189
- readonly contract: "deployment.result.v1";
190
- readonly ok: true;
191
- readonly status: "SUCCEEDED";
192
- readonly moduleRef: "agent-gateway";
193
- readonly moduleVersion: "0.1.4";
194
- };
195
39
  observedEffects: never[];
196
- };
197
- preflight: () => {
40
+ }>;
41
+ readonly setup: (context: ModuleCommandContext) => Promise<{
198
42
  result: {
199
43
  readonly contract: "deployment.result.v1";
200
44
  readonly ok: true;
201
45
  readonly status: "SUCCEEDED";
202
46
  readonly moduleRef: "agent-gateway";
203
- readonly moduleVersion: "0.1.4";
204
- };
205
- observedEffects: never[];
206
- };
207
- status: () => Promise<{
208
- result: {
47
+ readonly moduleVersion: "0.1.6";
48
+ } | {
209
49
  contract: "deployment.result.v1";
210
- ok: true;
211
- status: "SUCCEEDED";
212
50
  moduleRef: "agent-gateway";
213
- moduleVersion: "0.1.4";
214
- data: {
215
- configStatus: "INCOMPLETE" | "INVALID" | "READY";
216
- missingConfig?: string[] | undefined;
217
- runtimeStatus: "FAILED" | "RUNNING" | "STOPPED" | "UNKNOWN";
51
+ moduleVersion: "0.1.6";
52
+ ok: false;
53
+ status: "FAILED";
54
+ error: {
55
+ code: "SETUP_FAILED" | "START_FAILED" | "STOP_FAILED";
56
+ message: string;
57
+ retryable: boolean;
218
58
  };
219
59
  };
220
60
  observedEffects: never[];
221
61
  }>;
222
- verify: () => Promise<{
62
+ readonly docs: (_context: ModuleCommandContext) => Promise<{
223
63
  result: {
224
64
  contract: "deployment.result.v1";
225
65
  ok: true;
226
66
  status: "SUCCEEDED";
227
67
  moduleRef: "agent-gateway";
228
- moduleVersion: "0.1.4";
229
- checks: {
230
- id: string;
231
- status: "FAIL" | "PASS";
232
- message: string;
233
- }[];
234
- } | {
235
- contract: "deployment.result.v1";
236
- moduleRef: "agent-gateway";
237
- moduleVersion: "0.1.4";
238
- ok: false;
239
- status: "ACTION_REQUIRED";
240
- actionRequired: {
241
- readonly action: "compose-gateway";
242
- readonly description: "Provide owner ports and process configuration";
243
- };
244
- checks: {
245
- id: string;
246
- status: "FAIL" | "PASS";
247
- message: string;
248
- }[];
249
- } | {
250
- contract: "deployment.result.v1";
251
- moduleRef: "agent-gateway";
252
- moduleVersion: "0.1.4";
253
- ok: false;
254
- status: "ACTION_REQUIRED";
255
- actionRequired: {
256
- action: string;
257
- description: string;
68
+ moduleVersion: "0.1.6";
69
+ data: {
70
+ docs: string;
71
+ setup: string;
258
72
  };
259
- checks: {
260
- id: string;
261
- status: "FAIL" | "PASS";
262
- message: string;
263
- }[];
264
73
  };
265
74
  observedEffects: never[];
266
75
  }>;
267
- doctor: () => {
268
- result: {
269
- readonly contract: "deployment.result.v1";
270
- readonly ok: true;
271
- readonly status: "SUCCEEDED";
272
- readonly moduleRef: "agent-gateway";
273
- readonly moduleVersion: "0.1.4";
274
- };
275
- observedEffects: never[];
276
- };
277
- start: () => Promise<{
76
+ readonly start: (context: ModuleCommandContext) => Promise<{
278
77
  result: {
279
78
  contract: "deployment.result.v1";
280
79
  ok: true;
281
80
  status: "SUCCEEDED";
282
81
  moduleRef: "agent-gateway";
283
- moduleVersion: "0.1.4";
82
+ moduleVersion: "0.1.6";
284
83
  data: {
285
84
  host: string;
286
85
  port: number;
287
86
  };
288
- } | {
87
+ };
88
+ observedEffects: string[];
89
+ } | {
90
+ result: {
289
91
  contract: "deployment.result.v1";
290
92
  moduleRef: "agent-gateway";
291
- moduleVersion: "0.1.4";
292
- status: "ACTION_REQUIRED";
293
- ok: boolean;
294
- actionRequired: {
295
- action: string;
296
- description: string;
93
+ moduleVersion: "0.1.6";
94
+ ok: false;
95
+ status: "FAILED";
96
+ error: {
97
+ code: "SETUP_FAILED" | "START_FAILED" | "STOP_FAILED";
98
+ message: string;
99
+ retryable: boolean;
297
100
  };
298
101
  };
299
- observedEffects: string[];
102
+ observedEffects: never[];
300
103
  }>;
301
- stop: () => Promise<{
104
+ readonly stop: (context: ModuleCommandContext) => Promise<{
302
105
  result: {
303
106
  readonly contract: "deployment.result.v1";
304
107
  readonly ok: true;
305
108
  readonly status: "SUCCEEDED";
306
109
  readonly moduleRef: "agent-gateway";
307
- readonly moduleVersion: "0.1.4";
308
- } | {
309
- readonly contract: "deployment.result.v1";
310
- readonly moduleRef: "agent-gateway";
311
- readonly moduleVersion: "0.1.4";
312
- readonly ok: false;
313
- readonly status: "ACTION_REQUIRED";
314
- readonly actionRequired: {
315
- readonly action: "compose-gateway";
316
- readonly description: "Provide owner ports and process configuration";
317
- };
110
+ readonly moduleVersion: "0.1.6";
318
111
  };
319
112
  observedEffects: string[];
320
- }>;
321
- uninstall: () => Promise<{
113
+ } | {
322
114
  result: {
323
115
  readonly contract: "deployment.result.v1";
324
116
  readonly ok: true;
325
117
  readonly status: "SUCCEEDED";
326
118
  readonly moduleRef: "agent-gateway";
327
- readonly moduleVersion: "0.1.4";
328
- };
329
- observedEffects: string[];
330
- }>;
331
- restart: () => Promise<{
332
- result: {
333
- contract: "deployment.result.v1";
334
- ok: true;
335
- status: "SUCCEEDED";
336
- moduleRef: "agent-gateway";
337
- moduleVersion: "0.1.4";
338
- data: {
339
- host: string;
340
- port: number;
341
- };
119
+ readonly moduleVersion: "0.1.6";
342
120
  } | {
343
121
  contract: "deployment.result.v1";
344
122
  moduleRef: "agent-gateway";
345
- moduleVersion: "0.1.4";
346
- status: "ACTION_REQUIRED";
347
- ok: boolean;
348
- actionRequired: {
349
- action: string;
350
- description: string;
123
+ moduleVersion: "0.1.6";
124
+ ok: false;
125
+ status: "FAILED";
126
+ error: {
127
+ code: "SETUP_FAILED" | "START_FAILED" | "STOP_FAILED";
128
+ message: string;
129
+ retryable: boolean;
351
130
  };
352
131
  };
353
- observedEffects: string[];
132
+ observedEffects: never[];
354
133
  }>;
355
134
  };
356
- export declare function createProductionBinding(input: {
357
- moduleRef: string;
358
- config: Record<string, string>;
359
- workspaceRoot: string;
360
- configByModuleRef: ReadonlyMap<string, Record<string, string>>;
361
- }): Promise<{
362
- behaviorAdapter: Record<string, unknown>;
363
- }>;
364
- export {};
@@ -1,5 +1,8 @@
1
- import { observeDeclaredModuleStatus } from "@tomflow/proflow-module-contract";
1
+ import { existsSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { deterministicLoopbackPort, readModuleSharedFacts, writeModuleSharedFacts, } from "@tomflow/proflow-module-contract";
2
4
  import { descriptor } from "./descriptor.js";
5
+ const services = new Map();
3
6
  const base = {
4
7
  contract: "deployment.result.v1",
5
8
  ok: true,
@@ -7,170 +10,141 @@ const base = {
7
10
  moduleRef: descriptor.moduleRef,
8
11
  moduleVersion: descriptor.moduleVersion,
9
12
  };
10
- const unbound = {
13
+ const key = (context) => resolve(context.workspaceRoot);
14
+ const factString = (facts, name) => (typeof facts?.[name] === "string" ? String(facts[name]) : undefined);
15
+ async function ownFacts(context) {
16
+ const localBaseUrl = `http://127.0.0.1:${deterministicLoopbackPort(context, descriptor.moduleRef)}`;
17
+ const tunnel = await readModuleSharedFacts(context, "dev-tunnel");
18
+ const publicBaseUrl = factString(tunnel, "publicBaseUrl");
19
+ const facts = { localBaseUrl, ...(publicBaseUrl ? { publicBaseUrl } : {}) };
20
+ await writeModuleSharedFacts(context, descriptor.moduleRef, facts);
21
+ return facts;
22
+ }
23
+ async function dependencies(context) {
24
+ const tunnel = await readModuleSharedFacts(context, "dev-tunnel");
25
+ const host = await readModuleSharedFacts(context, "platform-host");
26
+ const publicBaseUrl = factString(tunnel, "publicBaseUrl");
27
+ const downstreamBaseUrl = factString(host, "endpoint");
28
+ const downstreamCredentialFile = factString(host, "gatewayTransportCredentialFile");
29
+ const stateRoot = factString(host, "stateRoot");
30
+ return publicBaseUrl &&
31
+ downstreamBaseUrl &&
32
+ downstreamCredentialFile &&
33
+ stateRoot
34
+ ? { publicBaseUrl, downstreamBaseUrl, downstreamCredentialFile, stateRoot }
35
+ : undefined;
36
+ }
37
+ async function running(context) {
38
+ const own = await ownFacts(context);
39
+ try {
40
+ return (await fetch(`${own.localBaseUrl}/ready`, {
41
+ signal: AbortSignal.timeout(500),
42
+ })).ok;
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ }
48
+ async function compose(context) {
49
+ const own = await ownFacts(context);
50
+ const deps = await dependencies(context);
51
+ if (!deps)
52
+ throw new Error("public-ingress or platform-host shared facts are unavailable");
53
+ const credentialFile = join(deps.stateRoot, "agent", "secrets", "role-credentials.json");
54
+ if (!existsSync(credentialFile))
55
+ throw new Error("Agent role credential store is not materialized by Platform Host");
56
+ const { createAgentGatewayProcess, parseAgentGatewayProcessConfig } = await import("../src/process.js");
57
+ const listener = new URL(own.localBaseUrl);
58
+ return createAgentGatewayProcess({
59
+ config: parseAgentGatewayProcessConfig({
60
+ host: listener.hostname,
61
+ port: Number(listener.port),
62
+ publicBaseUrl: deps.publicBaseUrl,
63
+ downstreamBaseUrl: deps.downstreamBaseUrl,
64
+ credentialFile,
65
+ downstreamCredentialFile: deps.downstreamCredentialFile,
66
+ }),
67
+ });
68
+ }
69
+ const failed = (code, message) => ({
11
70
  ...base,
12
71
  ok: false,
13
- status: "ACTION_REQUIRED",
14
- actionRequired: {
15
- action: "compose-gateway",
16
- description: "Provide owner ports and process configuration",
72
+ status: "FAILED",
73
+ error: { code, message, retryable: true },
74
+ });
75
+ export const behaviorAdapter = {
76
+ install: async (context) => ({
77
+ result: { ...base, data: await ownFacts(context) },
78
+ observedEffects: [],
79
+ }),
80
+ uninstall: async (context) => {
81
+ const service = services.get(key(context));
82
+ if (service) {
83
+ await service.stop();
84
+ services.delete(key(context));
85
+ }
86
+ return {
87
+ result: base,
88
+ observedEffects: service ? ["Manage the declared service process"] : [],
89
+ };
17
90
  },
18
- };
19
- export function createBehaviorAdapter(service, config, configValid = true) {
20
- return {
21
- describe: () => ({ result: base, observedEffects: [] }),
22
- preflight: () => ({ result: base, observedEffects: [] }),
23
- status: async () => {
24
- const readiness = service ? await service.readiness() : undefined;
25
- const ready = readiness?.status === "READY";
26
- const data = observeDeclaredModuleStatus(descriptor, config, ready ? "RUNNING" : service ? "FAILED" : "UNKNOWN", configValid);
91
+ status: async (context) => ({
92
+ result: {
93
+ ...base,
94
+ data: {
95
+ setupStatus: (await dependencies(context))
96
+ ? "READY"
97
+ : "FAILED",
98
+ runtimeStatus: (await running(context))
99
+ ? "RUNNING"
100
+ : "STOPPED",
101
+ },
102
+ },
103
+ observedEffects: [],
104
+ }),
105
+ setup: async (context) => ({
106
+ result: (await dependencies(context))
107
+ ? base
108
+ : failed("SETUP_FAILED", "public-ingress or platform-host producer shared facts are unavailable"),
109
+ observedEffects: [],
110
+ }),
111
+ docs: async (_context) => ({
112
+ result: { ...base, data: { docs: "DOCS.md", setup: "SETUP.md" } },
113
+ observedEffects: [],
114
+ }),
115
+ start: async (context) => {
116
+ try {
117
+ const service = await compose(context);
118
+ const data = await service.start();
119
+ services.set(key(context), service);
120
+ await ownFacts(context);
27
121
  return {
28
122
  result: { ...base, data },
29
- observedEffects: [],
123
+ observedEffects: ["Manage the declared service process"],
30
124
  };
31
- },
32
- verify: async () => {
33
- const readiness = service ? await service.readiness() : undefined;
34
- const ready = readiness?.status === "READY";
125
+ }
126
+ catch (error) {
35
127
  return {
36
- result: {
37
- ...(service && ready
38
- ? base
39
- : service
40
- ? {
41
- ...base,
42
- ok: false,
43
- status: "ACTION_REQUIRED",
44
- actionRequired: {
45
- action: "repair-gateway",
46
- description: "Gateway is not READY",
47
- },
48
- }
49
- : unbound),
50
- checks: [
51
- {
52
- id: "gateway-readiness",
53
- status: ready ? "PASS" : "FAIL",
54
- message: service
55
- ? `Gateway readiness is ${readiness?.status ?? "NOT_READY"}`
56
- : "No configured Gateway process is bound",
57
- },
58
- ],
59
- },
128
+ result: failed("START_FAILED", error instanceof Error ? error.message : "agent-gateway start failed"),
60
129
  observedEffects: [],
61
130
  };
62
- },
63
- doctor: () => ({ result: base, observedEffects: [] }),
64
- start: async () => ({
65
- result: {
66
- ...base,
67
- ...(service
68
- ? { data: await service.start() }
69
- : {
70
- status: "ACTION_REQUIRED",
71
- ok: false,
72
- actionRequired: {
73
- action: "compose-gateway",
74
- description: "Provide owner ports before starting Gateway",
75
- },
76
- }),
77
- },
78
- observedEffects: service ? ["Manage the declared service process"] : [],
79
- }),
80
- stop: async () => {
81
- if (service)
82
- await service.stop();
83
- return {
84
- result: service ? base : unbound,
85
- observedEffects: service ? ["Manage the declared service process"] : [],
86
- };
87
- },
88
- uninstall: async () => {
89
- if (service)
90
- await service.stop();
131
+ }
132
+ },
133
+ stop: async (context) => {
134
+ const service = services.get(key(context));
135
+ if (service) {
136
+ await service.stop();
137
+ services.delete(key(context));
91
138
  return {
92
- // Uninstall is idempotent: an unbound service means there is no
93
- // process to stop before package removal. Runtime readiness still
94
- // fails closed in status/start/verify.
95
139
  result: base,
96
- observedEffects: service ? ["Manage the declared service process"] : [],
140
+ observedEffects: ["Manage the declared service process"],
97
141
  };
98
- },
99
- restart: async () => ({
100
- result: {
101
- ...base,
102
- ...(service
103
- ? { data: await service.restart() }
104
- : {
105
- status: "ACTION_REQUIRED",
106
- ok: false,
107
- actionRequired: {
108
- action: "compose-gateway",
109
- description: "Provide owner ports before restarting Gateway",
110
- },
111
- }),
112
- },
113
- observedEffects: service ? ["Manage the declared service process"] : [],
114
- }),
115
- };
116
- }
117
- export const behaviorAdapter = createBehaviorAdapter();
118
- export async function createProductionBinding(input) {
119
- const unboundBinding = (configValid = true) => ({
120
- behaviorAdapter: createBehaviorAdapter(undefined, input.config, configValid),
121
- });
122
- const localBaseUrl = input.config.localBaseUrl;
123
- const publicBaseUrl = input.config.publicBaseUrl;
124
- const downstreamCredentialFile = input.config.downstreamCredentialFile;
125
- if (!localBaseUrl || !publicBaseUrl || !downstreamCredentialFile)
126
- return unboundBinding();
127
- let listener;
128
- let publicUrl;
129
- try {
130
- listener = new URL(localBaseUrl);
131
- publicUrl = new URL(publicBaseUrl);
132
- }
133
- catch {
134
- return unboundBinding(false);
135
- }
136
- if (listener.protocol !== "http:" ||
137
- !new Set(["127.0.0.1", "localhost", "::1", "[::1]"]).has(listener.hostname) ||
138
- listener.pathname !== "/" ||
139
- publicUrl.protocol !== "https:")
140
- return unboundBinding(false);
141
- const port = listener.port === "" ? 80 : Number(listener.port);
142
- if (!Number.isInteger(port) || port <= 0 || port > 65_535)
143
- return unboundBinding(false);
144
- const platformHost = input.configByModuleRef.get("platform-host");
145
- const executionRuntime = input.configByModuleRef.get("execution-runtime");
146
- const stateRoot = platformHost?.stateRoot;
147
- const downstreamBaseUrl = executionRuntime?.["identity.endpoint"];
148
- if (!stateRoot || !downstreamBaseUrl)
149
- return unboundBinding();
150
- try {
151
- const downstream = new URL(downstreamBaseUrl);
152
- if (downstream.protocol !== "http:" ||
153
- !["localhost", "127.0.0.1", "::1"].includes(downstream.hostname))
154
- return unboundBinding();
155
- }
156
- catch {
157
- return unboundBinding();
158
- }
159
- const [{ join }, { createAgentGatewayProcess, parseAgentGatewayProcessConfig },] = await Promise.all([import("node:path"), import("../src/process.js")]);
160
- let processConfig;
161
- try {
162
- processConfig = parseAgentGatewayProcessConfig({
163
- host: listener.hostname,
164
- port,
165
- publicBaseUrl,
166
- downstreamBaseUrl,
167
- credentialFile: join(stateRoot, "agent", "secrets", "role-credentials.json"),
168
- downstreamCredentialFile,
169
- });
170
- }
171
- catch {
172
- return unboundBinding(false);
173
- }
174
- const service = await createAgentGatewayProcess({ config: processConfig });
175
- return { behaviorAdapter: createBehaviorAdapter(service, input.config) };
176
- }
142
+ }
143
+ return {
144
+ result: (await running(context))
145
+ ? failed("STOP_FAILED", "agent-gateway is running without an owned lifecycle handle")
146
+ : base,
147
+ observedEffects: [],
148
+ };
149
+ },
150
+ };
@@ -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.4";
6
+ readonly moduleVersion: "0.1.6";
7
7
  readonly kind: "service";
8
8
  readonly templateVersion: "1.0.0";
9
9
  readonly platformCompatibility: ">=1.0.0 <2.0.0";
@@ -24,57 +24,26 @@ export declare const descriptor: {
24
24
  }, {
25
25
  readonly contractRef: "execution";
26
26
  readonly versionRange: ">=1.0.0 <2.0.0";
27
+ }, {
28
+ readonly contractRef: "platform-host";
29
+ readonly versionRange: ">=1.0.0 <2.0.0";
30
+ }, {
31
+ readonly contractRef: "public-ingress";
32
+ readonly versionRange: ">=1.0.0 <2.0.0";
27
33
  }];
28
34
  readonly requirements: readonly [{
29
35
  readonly kind: "runtime";
30
36
  readonly runtime: "node";
31
37
  readonly versionRange: ">=24.19.0";
32
38
  }];
33
- readonly configSlots: readonly [{
34
- readonly key: "localBaseUrl";
35
- readonly type: "url";
36
- readonly required: true;
37
- readonly description: "Loopback HTTP listener URL owned by Agent Gateway and targeted by the public ingress resource";
38
- }, {
39
- readonly key: "publicBaseUrl";
40
- readonly type: "url";
41
- readonly required: true;
42
- readonly description: "Public HTTPS URL supplied by the dev-tunnel resource";
43
- }, {
44
- readonly key: "downstreamCredentialFile";
45
- readonly type: "path";
46
- readonly required: true;
47
- readonly sensitive: true;
48
- readonly description: "File containing the dedicated Gateway-to-platform-host transport credential";
49
- }, {
50
- readonly key: "publicIngressModuleRef";
51
- readonly type: "moduleRef";
52
- readonly required: false;
53
- readonly description: "External resource module governing the public ingress";
54
- readonly default: "dev-tunnel";
55
- }];
56
- readonly lifecycle: {
57
- readonly supported: readonly ["describe", "preflight", "status", "verify", "doctor", "start", "stop", "restart", "uninstall"];
58
- };
59
- readonly verification: {
60
- readonly checks: readonly [{
61
- readonly id: "gateway-readiness";
62
- readonly description: "Gateway dependencies and transport guards are ready";
63
- readonly lifecycle: "verify";
64
- }];
65
- };
39
+ readonly configSlots: readonly [];
66
40
  readonly effects: readonly [{
67
41
  readonly kind: "process";
68
42
  readonly description: "Manage the declared service process";
69
43
  readonly retention: "remove";
70
44
  }];
71
- readonly documentation: readonly [{
72
- readonly id: "overview";
73
- readonly path: "./README.md";
74
- readonly description: "Agent Gateway package overview";
75
- }, {
76
- readonly id: "configuration";
77
- readonly path: "./CONFIGURATION.md";
78
- readonly description: "Module configuration fields, sources and materialization instructions";
79
- }];
45
+ readonly documentation: {
46
+ readonly docs: "DOCS.md";
47
+ readonly setup: "SETUP.md";
48
+ };
80
49
  };
@@ -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.4",
6
+ moduleVersion: "0.1.6",
7
7
  kind: "service",
8
8
  templateVersion: "1.0.0",
9
9
  platformCompatibility: ">=1.0.0 <2.0.0",
@@ -30,6 +30,14 @@ export const descriptor = {
30
30
  contractRef: "execution",
31
31
  versionRange: ">=1.0.0 <2.0.0",
32
32
  },
33
+ {
34
+ contractRef: "platform-host",
35
+ versionRange: ">=1.0.0 <2.0.0",
36
+ },
37
+ {
38
+ contractRef: "public-ingress",
39
+ versionRange: ">=1.0.0 <2.0.0",
40
+ },
33
41
  ],
34
42
  requirements: [
35
43
  {
@@ -38,56 +46,7 @@ export const descriptor = {
38
46
  versionRange: ">=24.19.0",
39
47
  },
40
48
  ],
41
- configSlots: [
42
- {
43
- key: "localBaseUrl",
44
- type: "url",
45
- required: true,
46
- description: "Loopback HTTP listener URL owned by Agent Gateway and targeted by the public ingress resource",
47
- },
48
- {
49
- key: "publicBaseUrl",
50
- type: "url",
51
- required: true,
52
- description: "Public HTTPS URL supplied by the dev-tunnel resource",
53
- },
54
- {
55
- key: "downstreamCredentialFile",
56
- type: "path",
57
- required: true,
58
- sensitive: true,
59
- description: "File containing the dedicated Gateway-to-platform-host transport credential",
60
- },
61
- {
62
- key: "publicIngressModuleRef",
63
- type: "moduleRef",
64
- required: false,
65
- description: "External resource module governing the public ingress",
66
- default: "dev-tunnel",
67
- },
68
- ],
69
- lifecycle: {
70
- supported: [
71
- "describe",
72
- "preflight",
73
- "status",
74
- "verify",
75
- "doctor",
76
- "start",
77
- "stop",
78
- "restart",
79
- "uninstall",
80
- ],
81
- },
82
- verification: {
83
- checks: [
84
- {
85
- id: "gateway-readiness",
86
- description: "Gateway dependencies and transport guards are ready",
87
- lifecycle: "verify",
88
- },
89
- ],
90
- },
49
+ configSlots: [],
91
50
  effects: [
92
51
  {
93
52
  kind: "process",
@@ -95,16 +54,8 @@ export const descriptor = {
95
54
  retention: "remove",
96
55
  },
97
56
  ],
98
- documentation: [
99
- {
100
- id: "overview",
101
- path: "./README.md",
102
- description: "Agent Gateway package overview",
103
- },
104
- {
105
- id: "configuration",
106
- path: "./CONFIGURATION.md",
107
- description: "Module configuration fields, sources and materialization instructions",
108
- },
109
- ],
57
+ documentation: {
58
+ docs: "DOCS.md",
59
+ setup: "SETUP.md",
60
+ },
110
61
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomflow/proflow-agent-gateway",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -20,22 +20,23 @@
20
20
  "proflow.module.json",
21
21
  "conformance.json",
22
22
  "README.md",
23
- "CONFIGURATION.md"
23
+ "DOCS.md",
24
+ "SETUP.md"
24
25
  ],
25
26
  "dependencies": {
26
27
  "zod": "4.1.12",
27
- "@tomflow/proflow-module-contract": "^0.1.1"
28
+ "@tomflow/proflow-module-contract": "^0.1.4"
28
29
  },
29
30
  "devDependencies": {
30
- "@tomflow/proflow-agent-runtime": "^0.1.2",
31
- "@tomflow/proflow-execution-local": "^0.1.3",
32
- "@tomflow/proflow-deployment-conformance": "^0.1.2",
33
- "@tomflow/proflow-task-store-sqlite": "^0.1.2",
34
- "@tomflow/proflow-task-migration-runner": "^0.1.2",
35
- "@tomflow/proflow-task-orchestration": "^0.1.1",
36
- "@tomflow/proflow-execution-browser-extension": "^0.1.3",
37
- "@tomflow/proflow-platform-host": "^0.1.4",
38
- "@tomflow/proflow-execution-runtime": "^0.1.5"
31
+ "@tomflow/proflow-agent-runtime": "^0.1.4",
32
+ "@tomflow/proflow-execution-browser-extension": "^0.1.5",
33
+ "@tomflow/proflow-platform-host": "^0.1.6",
34
+ "@tomflow/proflow-execution-local": "^0.1.5",
35
+ "@tomflow/proflow-task-migration-runner": "^0.1.4",
36
+ "@tomflow/proflow-execution-runtime": "^0.1.7",
37
+ "@tomflow/proflow-deployment-conformance": "^0.1.4",
38
+ "@tomflow/proflow-task-store-sqlite": "^0.1.4",
39
+ "@tomflow/proflow-task-orchestration": "^0.1.3"
39
40
  },
40
41
  "description": "The sole Custom GPT Actions HTTP ingress and OpenAI transport anti-corruption layer.",
41
42
  "keywords": [
@@ -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.4",
6
+ "moduleVersion": "0.1.6",
7
7
  "kind": "service",
8
8
  "templateVersion": "1.0.0",
9
9
  "platformCompatibility": ">=1.0.0 <2.0.0",
@@ -29,6 +29,14 @@
29
29
  {
30
30
  "contractRef": "execution",
31
31
  "versionRange": ">=1.0.0 <2.0.0"
32
+ },
33
+ {
34
+ "contractRef": "platform-host",
35
+ "versionRange": ">=1.0.0 <2.0.0"
36
+ },
37
+ {
38
+ "contractRef": "public-ingress",
39
+ "versionRange": ">=1.0.0 <2.0.0"
32
40
  }
33
41
  ],
34
42
  "requirements": [
@@ -38,56 +46,7 @@
38
46
  "versionRange": ">=24.19.0"
39
47
  }
40
48
  ],
41
- "configSlots": [
42
- {
43
- "key": "localBaseUrl",
44
- "type": "url",
45
- "required": true,
46
- "description": "Loopback HTTP listener URL owned by Agent Gateway and targeted by the public ingress resource"
47
- },
48
- {
49
- "key": "publicBaseUrl",
50
- "type": "url",
51
- "required": true,
52
- "description": "Public HTTPS URL supplied by the dev-tunnel resource"
53
- },
54
- {
55
- "key": "downstreamCredentialFile",
56
- "type": "path",
57
- "required": true,
58
- "sensitive": true,
59
- "description": "File containing the dedicated Gateway-to-platform-host transport credential"
60
- },
61
- {
62
- "key": "publicIngressModuleRef",
63
- "type": "moduleRef",
64
- "required": false,
65
- "description": "External resource module governing the public ingress",
66
- "default": "dev-tunnel"
67
- }
68
- ],
69
- "lifecycle": {
70
- "supported": [
71
- "describe",
72
- "preflight",
73
- "status",
74
- "verify",
75
- "doctor",
76
- "start",
77
- "stop",
78
- "restart",
79
- "uninstall"
80
- ]
81
- },
82
- "verification": {
83
- "checks": [
84
- {
85
- "id": "gateway-readiness",
86
- "description": "Gateway dependencies and transport guards are ready",
87
- "lifecycle": "verify"
88
- }
89
- ]
90
- },
49
+ "configSlots": [],
91
50
  "effects": [
92
51
  {
93
52
  "kind": "process",
@@ -95,16 +54,8 @@
95
54
  "retention": "remove"
96
55
  }
97
56
  ],
98
- "documentation": [
99
- {
100
- "id": "overview",
101
- "path": "./README.md",
102
- "description": "Agent Gateway package overview"
103
- },
104
- {
105
- "id": "configuration",
106
- "path": "./CONFIGURATION.md",
107
- "description": "Module configuration fields, sources and materialization instructions"
108
- }
109
- ]
57
+ "documentation": {
58
+ "docs": "DOCS.md",
59
+ "setup": "SETUP.md"
60
+ }
110
61
  }
package/CONFIGURATION.md DELETED
@@ -1,26 +0,0 @@
1
- # agent-gateway configuration
2
-
3
- Canonical public config: `.proflow/config/agent-gateway.json`
4
-
5
- This file is Workspace-owned data. `platform uninstall` does not delete it. Values are JSON strings. Raw secrets must not be stored here; `secretRef` fields contain opaque references only.
6
-
7
- ## Fields
8
-
9
- | Key | Type | Required | Sensitive | Source | Meaning |
10
- |---|---|---:|---:|---|---|
11
- | `localBaseUrl` | `url` | yes | no | User or owning external/runtime Module supplies the reachable endpoint URL. | Loopback HTTP listener URL owned by Agent Gateway and targeted by the public ingress resource |
12
- | `publicBaseUrl` | `url` | yes | no | User or owning external/runtime Module supplies the reachable endpoint URL. | Public HTTPS URL supplied by the dev-tunnel resource |
13
- | `downstreamCredentialFile` | `path` | yes | yes | User or owning Module supplies an absolute/local path that exists on this Workspace. | File containing the dedicated Gateway-to-platform-host transport credential |
14
- | `publicIngressModuleRef` | `moduleRef` | no | no | Another installed ProFlow Module reference selected from `platform docs` / Module topology. | External resource module governing the public ingress |
15
-
16
- ## Materialize
17
-
18
- Create or update the canonical JSON object at:
19
-
20
- `.proflow/config/agent-gateway.json`
21
-
22
- Use only declared keys and string values. Do not create a second Platform configuration database.
23
-
24
- ## Base completion check
25
-
26
- Run `platform modules`. This Module should no longer report required keys in `missingConfig`. `platform start` performs the authoritative Module-owned validation before starting anything.