@mono-agent/operator-adapter 0.4.1
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/README.md +95 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/live/config.d.ts +27 -0
- package/dist/live/config.d.ts.map +1 -0
- package/dist/live/config.js +67 -0
- package/dist/live/config.js.map +1 -0
- package/dist/live/constants.d.ts +18 -0
- package/dist/live/constants.d.ts.map +1 -0
- package/dist/live/constants.js +18 -0
- package/dist/live/constants.js.map +1 -0
- package/dist/live/errors.d.ts +12 -0
- package/dist/live/errors.d.ts.map +1 -0
- package/dist/live/errors.js +7 -0
- package/dist/live/errors.js.map +1 -0
- package/dist/live/index.d.ts +10 -0
- package/dist/live/index.d.ts.map +1 -0
- package/dist/live/index.js +8 -0
- package/dist/live/index.js.map +1 -0
- package/dist/live/server.d.ts +40 -0
- package/dist/live/server.d.ts.map +1 -0
- package/dist/live/server.js +219 -0
- package/dist/live/server.js.map +1 -0
- package/dist/tui/config.d.ts +28 -0
- package/dist/tui/config.d.ts.map +1 -0
- package/dist/tui/config.js +64 -0
- package/dist/tui/config.js.map +1 -0
- package/dist/tui/constants.d.ts +15 -0
- package/dist/tui/constants.d.ts.map +1 -0
- package/dist/tui/constants.js +15 -0
- package/dist/tui/constants.js.map +1 -0
- package/dist/tui/errors.d.ts +12 -0
- package/dist/tui/errors.d.ts.map +1 -0
- package/dist/tui/errors.js +7 -0
- package/dist/tui/errors.js.map +1 -0
- package/dist/tui/index.d.ts +8 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +5 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/server.d.ts +74 -0
- package/dist/tui/server.d.ts.map +1 -0
- package/dist/tui/server.js +292 -0
- package/dist/tui/server.js.map +1 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# @mono-agent/operator-adapter
|
|
2
|
+
|
|
3
|
+
## Category
|
|
4
|
+
|
|
5
|
+
Category: `communication`
|
|
6
|
+
|
|
7
|
+
## Responsibility
|
|
8
|
+
|
|
9
|
+
Loopback operator endpoints for local mono-agent surfaces:
|
|
10
|
+
|
|
11
|
+
- the TUI NDJSON turn endpoint, which lets `mono-agent tui` chat with a running
|
|
12
|
+
agent at full `AgentStreamEvent` fidelity.
|
|
13
|
+
- the live SSE event relay, which streams the host's in-process run-event bus to
|
|
14
|
+
read-only operator surfaces such as `mono-agent web`.
|
|
15
|
+
|
|
16
|
+
Both endpoints keep their existing wire contracts, routes, env vars, defaults,
|
|
17
|
+
auth behavior, and error behavior.
|
|
18
|
+
|
|
19
|
+
## Install / Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm --filter @mono-agent/operator-adapter run build
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import {
|
|
27
|
+
createLiveEventBus,
|
|
28
|
+
startLiveAdapter,
|
|
29
|
+
startTuiAdapter,
|
|
30
|
+
} from "@mono-agent/operator-adapter";
|
|
31
|
+
|
|
32
|
+
const tui = await startTuiAdapter({
|
|
33
|
+
responder,
|
|
34
|
+
info: { label: "personal-agent", model: "claude-fable-5" },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const bus = createLiveEventBus();
|
|
38
|
+
const live = await startLiveAdapter({ bus, host: "127.0.0.1", port: 0 });
|
|
39
|
+
|
|
40
|
+
await tui.stop();
|
|
41
|
+
await live.stop();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### TUI Endpoints
|
|
45
|
+
|
|
46
|
+
- `GET {basePath}/v1/info` - `{ schema, pid, label?, model?, effort? }`.
|
|
47
|
+
- `POST {basePath}/v1/turns` - body `{ conversationId, text, metadata? }`;
|
|
48
|
+
responds with chunked `application/x-ndjson` frames
|
|
49
|
+
(`status | append | replace | event | finish | error`). Closing the socket
|
|
50
|
+
aborts the in-flight turn.
|
|
51
|
+
- `POST {basePath}/v1/conversations/:id/cancel` - explicit cancel (202; 501
|
|
52
|
+
when the responder has no `cancel`).
|
|
53
|
+
|
|
54
|
+
### Live Endpoints
|
|
55
|
+
|
|
56
|
+
- `GET {basePath}/v1/info` - `{ schema, pid, label? }`.
|
|
57
|
+
- `GET {basePath}/v1/events` - `text/event-stream` replaying recent
|
|
58
|
+
`RunEventFrame` values and streaming future frames.
|
|
59
|
+
|
|
60
|
+
## Public API
|
|
61
|
+
|
|
62
|
+
- TUI: `startTuiAdapter`, `loadTuiAdapterConfig`,
|
|
63
|
+
`redactTuiAdapterConfig`, `TUI_CONFIG_FIELDS`, `MAX_FRAME_BYTES`,
|
|
64
|
+
`DEFAULT_TUI_BASE_PATH`, `TUI_WIRE_SCHEMA`, `TuiAdapterError`, and the TUI
|
|
65
|
+
option/config/result/error types.
|
|
66
|
+
- Live: `startLiveAdapter`, `loadLiveAdapterConfig`,
|
|
67
|
+
`redactLiveAdapterConfig`, `LIVE_CONFIG_FIELDS`, `DEFAULT_LIVE_BASE_PATH`,
|
|
68
|
+
`LIVE_ADAPTER_INFO_SCHEMA`, `LiveAdapterError`, and the live
|
|
69
|
+
option/config/result/error types.
|
|
70
|
+
- Live bus/contracts re-exported from `@mono-agent/agent-contracts`:
|
|
71
|
+
`createLiveEventBus`, `LIVE_EVENT_SCHEMA`, `RunEventBus`, `RunEventFrame`,
|
|
72
|
+
`RunEventSink`, and `CreateLiveEventBusOptions`.
|
|
73
|
+
|
|
74
|
+
## Dependency Boundary
|
|
75
|
+
|
|
76
|
+
This adapter depends on Express plus shared `@mono-agent/agent-contracts`
|
|
77
|
+
primitives. It must not depend on the agent harness, runtime adapter, operator
|
|
78
|
+
surfaces, memory, observability, other communication adapters, or host/demo
|
|
79
|
+
code. Hosts compose it with structural responders and an optional run-event bus.
|
|
80
|
+
|
|
81
|
+
## What This Package Does Not Own
|
|
82
|
+
|
|
83
|
+
It does not build prompts, run models, persist conversations, discover running
|
|
84
|
+
agents, render operator UIs, interpret live events, implement replay/config
|
|
85
|
+
views, or own TLS/public deployment policy. Both servers bind loopback-only by
|
|
86
|
+
default; exposing either endpoint beyond loopback is a host decision guarded by
|
|
87
|
+
`allowNonLoopback`.
|
|
88
|
+
|
|
89
|
+
## Verification
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pnpm --filter @mono-agent/operator-adapter run build
|
|
93
|
+
pnpm --filter @mono-agent/operator-adapter run typecheck
|
|
94
|
+
pnpm --filter @mono-agent/operator-adapter run test
|
|
95
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { TuiAdapterError } from "./tui/index.js";
|
|
2
|
+
export type { TuiAdapterErrorCode, TuiAdapterErrorDetails } from "./tui/index.js";
|
|
3
|
+
export { startTuiAdapter } from "./tui/index.js";
|
|
4
|
+
export type { TuiAdapterInfo, TuiAdapterLogger, TuiAdapterOptions, TuiAdapterStartResult, } from "./tui/index.js";
|
|
5
|
+
export { loadTuiAdapterConfig, redactTuiAdapterConfig, TUI_CONFIG_FIELDS, } from "./tui/index.js";
|
|
6
|
+
export type { LoadTuiAdapterConfigInput, RedactedTuiAdapterConfig, TuiAdapterConfig, } from "./tui/index.js";
|
|
7
|
+
export { DEFAULT_BASE_PATH as DEFAULT_TUI_BASE_PATH, DEFAULT_HOST as DEFAULT_TUI_HOST, DEFAULT_PORT as DEFAULT_TUI_PORT, MAX_FRAME_BYTES, TUI_WIRE_SCHEMA, } from "./tui/constants.js";
|
|
8
|
+
export { startLiveAdapter } from "./live/index.js";
|
|
9
|
+
export type { LiveAdapterHandle, LiveAdapterLogger, LiveAdapterOptions, } from "./live/index.js";
|
|
10
|
+
export { LiveAdapterError } from "./live/index.js";
|
|
11
|
+
export type { LiveAdapterErrorCode, LiveAdapterErrorDetails } from "./live/index.js";
|
|
12
|
+
export { loadLiveAdapterConfig, redactLiveAdapterConfig, LIVE_CONFIG_FIELDS } from "./live/index.js";
|
|
13
|
+
export type { LiveAdapterConfig, RedactedLiveAdapterConfig, LoadLiveAdapterConfigInput, } from "./live/index.js";
|
|
14
|
+
export { DEFAULT_LIVE_BASE_PATH, DEFAULT_LIVE_HOST, DEFAULT_LIVE_PORT, LIVE_ADAPTER_INFO_SCHEMA, LIVE_HEARTBEAT_INTERVAL_MS, } from "./live/index.js";
|
|
15
|
+
export { LIVE_EVENT_SCHEMA, createLiveEventBus } from "./live/index.js";
|
|
16
|
+
export type { CreateLiveEventBusOptions, RunEventBus, RunEventFrame, RunEventSink, } from "./live/index.js";
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,yBAAyB,EACzB,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,iBAAiB,IAAI,qBAAqB,EAC1C,YAAY,IAAI,gBAAgB,EAChC,YAAY,IAAI,gBAAgB,EAChC,eAAe,EACf,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrG,YAAY,EACV,iBAAiB,EACjB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACxE,YAAY,EACV,yBAAyB,EACzB,WAAW,EACX,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { TuiAdapterError } from "./tui/index.js";
|
|
2
|
+
export { startTuiAdapter } from "./tui/index.js";
|
|
3
|
+
export { loadTuiAdapterConfig, redactTuiAdapterConfig, TUI_CONFIG_FIELDS, } from "./tui/index.js";
|
|
4
|
+
export { DEFAULT_BASE_PATH as DEFAULT_TUI_BASE_PATH, DEFAULT_HOST as DEFAULT_TUI_HOST, DEFAULT_PORT as DEFAULT_TUI_PORT, MAX_FRAME_BYTES, TUI_WIRE_SCHEMA, } from "./tui/constants.js";
|
|
5
|
+
export { startLiveAdapter } from "./live/index.js";
|
|
6
|
+
export { LiveAdapterError } from "./live/index.js";
|
|
7
|
+
export { loadLiveAdapterConfig, redactLiveAdapterConfig, LIVE_CONFIG_FIELDS } from "./live/index.js";
|
|
8
|
+
export { DEFAULT_LIVE_BASE_PATH, DEFAULT_LIVE_HOST, DEFAULT_LIVE_PORT, LIVE_ADAPTER_INFO_SCHEMA, LIVE_HEARTBEAT_INTERVAL_MS, } from "./live/index.js";
|
|
9
|
+
export { LIVE_EVENT_SCHEMA, createLiveEventBus } from "./live/index.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAOjD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EACL,iBAAiB,IAAI,qBAAqB,EAC1C,YAAY,IAAI,gBAAgB,EAChC,YAAY,IAAI,gBAAgB,EAChC,eAAe,EACf,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAMnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAMrG,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { JsonEnvFieldSpec, RedactedSecretValue, SettingsJson } from "@mono-agent/agent-contracts";
|
|
2
|
+
export interface LiveAdapterConfig {
|
|
3
|
+
readonly enabled: boolean;
|
|
4
|
+
readonly host: string;
|
|
5
|
+
readonly port: number;
|
|
6
|
+
readonly basePath: string;
|
|
7
|
+
readonly allowNonLoopback: boolean;
|
|
8
|
+
readonly apiKey?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface RedactedLiveAdapterConfig extends Omit<LiveAdapterConfig, "apiKey"> {
|
|
11
|
+
readonly apiKey: RedactedSecretValue;
|
|
12
|
+
}
|
|
13
|
+
export interface LoadLiveAdapterConfigInput {
|
|
14
|
+
readonly env: Record<string, string | undefined>;
|
|
15
|
+
readonly json?: SettingsJson;
|
|
16
|
+
readonly jsonPath?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function loadLiveAdapterConfig(input: LoadLiveAdapterConfigInput): Promise<LiveAdapterConfig>;
|
|
19
|
+
export declare function redactLiveAdapterConfig(config: LiveAdapterConfig): RedactedLiveAdapterConfig;
|
|
20
|
+
/**
|
|
21
|
+
* The `live` section's field registry: the single source of truth for JSON→env
|
|
22
|
+
* layering and the app's config provenance view. The `live.apiKey` id doubles as
|
|
23
|
+
* a cross-package contract — `mono-agent web` resolves a running agent's key by
|
|
24
|
+
* reading this field from the agent's config file (the registry carries no secrets).
|
|
25
|
+
*/
|
|
26
|
+
export declare const LIVE_CONFIG_FIELDS: readonly JsonEnvFieldSpec[];
|
|
27
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/live/config.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKvG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,yBAA0B,SAAQ,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC;IAClF,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;CACtC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAcD,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,iBAAiB,CAAC,CAoB5B;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,yBAAyB,CAS5F;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,gBAAgB,EAOzD,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { fieldSpecMappings, layerJsonOntoEnv, normalizeOptionalString, readBoolean, readInteger, readJsonSection, readSettingsJson, readString, redactedSecret, } from "@mono-agent/agent-contracts";
|
|
2
|
+
import { DEFAULT_LIVE_BASE_PATH, DEFAULT_LIVE_HOST, DEFAULT_LIVE_PORT } from "./constants.js";
|
|
3
|
+
import { LiveAdapterError } from "./errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* Like the TUI endpoint (and unlike every chat channel, default OFF), the live
|
|
6
|
+
* event relay is ON by default: it is a read-only operator surface, binds
|
|
7
|
+
* loopback-only on an ephemeral port, and needs no credentials — so
|
|
8
|
+
* `mono-agent web` can observe any running agent without a per-agent config edit.
|
|
9
|
+
* Set `"live": { "enabled": false }` to opt out.
|
|
10
|
+
*/
|
|
11
|
+
const DEFAULT_ENABLED = true;
|
|
12
|
+
const invalidConfig = (message, details) => new LiveAdapterError("invalid_config", message, details);
|
|
13
|
+
export async function loadLiveAdapterConfig(input) {
|
|
14
|
+
const json = input.json ?? (input.jsonPath === undefined ? {} : (await readSettingsJson(input.jsonPath)).json);
|
|
15
|
+
const env = layerLiveJsonOntoEnv(json, input.env);
|
|
16
|
+
const apiKey = normalizeOptionalString(env.MONO_AGENT_LIVE_API_KEY);
|
|
17
|
+
return {
|
|
18
|
+
enabled: readBoolean(env.MONO_AGENT_LIVE_ENABLED, "MONO_AGENT_LIVE_ENABLED", DEFAULT_ENABLED, invalidConfig),
|
|
19
|
+
host: readString(env.MONO_AGENT_LIVE_HOST, DEFAULT_LIVE_HOST),
|
|
20
|
+
port: readInteger(env.MONO_AGENT_LIVE_PORT, "MONO_AGENT_LIVE_PORT", DEFAULT_LIVE_PORT, invalidConfig, {
|
|
21
|
+
min: 0,
|
|
22
|
+
max: 65535,
|
|
23
|
+
}),
|
|
24
|
+
basePath: readBasePath(env.MONO_AGENT_LIVE_BASE_PATH),
|
|
25
|
+
allowNonLoopback: readBoolean(env.MONO_AGENT_LIVE_ALLOW_NON_LOOPBACK, "MONO_AGENT_LIVE_ALLOW_NON_LOOPBACK", false, invalidConfig),
|
|
26
|
+
...(apiKey === undefined ? {} : { apiKey }),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function redactLiveAdapterConfig(config) {
|
|
30
|
+
return {
|
|
31
|
+
enabled: config.enabled,
|
|
32
|
+
host: config.host,
|
|
33
|
+
port: config.port,
|
|
34
|
+
basePath: config.basePath,
|
|
35
|
+
allowNonLoopback: config.allowNonLoopback,
|
|
36
|
+
apiKey: redactedSecret(config.apiKey),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The `live` section's field registry: the single source of truth for JSON→env
|
|
41
|
+
* layering and the app's config provenance view. The `live.apiKey` id doubles as
|
|
42
|
+
* a cross-package contract — `mono-agent web` resolves a running agent's key by
|
|
43
|
+
* reading this field from the agent's config file (the registry carries no secrets).
|
|
44
|
+
*/
|
|
45
|
+
export const LIVE_CONFIG_FIELDS = [
|
|
46
|
+
{ id: "live.enabled", env: "MONO_AGENT_LIVE_ENABLED", kind: "boolean", fromJson: (s) => s.enabled },
|
|
47
|
+
{ id: "live.host", env: "MONO_AGENT_LIVE_HOST", fromJson: (s) => s.host },
|
|
48
|
+
{ id: "live.port", env: "MONO_AGENT_LIVE_PORT", kind: "integer", fromJson: (s) => s.port },
|
|
49
|
+
{ id: "live.basePath", env: "MONO_AGENT_LIVE_BASE_PATH", fromJson: (s) => s.basePath },
|
|
50
|
+
{ id: "live.allowNonLoopback", env: "MONO_AGENT_LIVE_ALLOW_NON_LOOPBACK", kind: "boolean", fromJson: (s) => s.allowNonLoopback },
|
|
51
|
+
{ id: "live.apiKey", env: "MONO_AGENT_LIVE_API_KEY", secret: true, fromJson: (s) => s.apiKey },
|
|
52
|
+
];
|
|
53
|
+
function layerLiveJsonOntoEnv(json, env) {
|
|
54
|
+
return layerJsonOntoEnv(env, fieldSpecMappings(readJsonSection(json, "live"), LIVE_CONFIG_FIELDS));
|
|
55
|
+
}
|
|
56
|
+
function readBasePath(raw) {
|
|
57
|
+
const value = readString(raw, DEFAULT_LIVE_BASE_PATH);
|
|
58
|
+
if (!isLiteralBasePath(value)) {
|
|
59
|
+
throw invalidConfig("MONO_AGENT_LIVE_BASE_PATH must be an absolute literal path made of slash-separated URL path segments.");
|
|
60
|
+
}
|
|
61
|
+
const stripped = value.replace(/\/+$/u, "");
|
|
62
|
+
return stripped.length === 0 ? "/" : stripped;
|
|
63
|
+
}
|
|
64
|
+
function isLiteralBasePath(basePath) {
|
|
65
|
+
return basePath === "/" || /^\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*\/?$/u.test(basePath);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/live/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Loopback-only default bind host — the adapter refuses non-loopback unless explicitly allowed. */
|
|
2
|
+
export declare const DEFAULT_LIVE_HOST = "127.0.0.1";
|
|
3
|
+
/** Default TCP port. `0` lets the OS pick a free ephemeral port (read back from the handle's baseUrl). */
|
|
4
|
+
export declare const DEFAULT_LIVE_PORT = 0;
|
|
5
|
+
/** Default URL prefix under which the adapter mounts `/v1/info` and `/v1/events`. */
|
|
6
|
+
export declare const DEFAULT_LIVE_BASE_PATH = "/live";
|
|
7
|
+
/**
|
|
8
|
+
* Schema tag surfaced by GET /v1/info so a discovery probe can identify the
|
|
9
|
+
* adapter and its wire version before subscribing to the event stream.
|
|
10
|
+
*/
|
|
11
|
+
export declare const LIVE_ADAPTER_INFO_SCHEMA = "live-adapter.v1";
|
|
12
|
+
/**
|
|
13
|
+
* Interval between SSE heartbeat comment lines (`: ping\n\n`). Heartbeats keep
|
|
14
|
+
* idle proxies/clients from dropping the connection between runs; the comment
|
|
15
|
+
* form carries no data and is ignored by SSE parsers.
|
|
16
|
+
*/
|
|
17
|
+
export declare const LIVE_HEARTBEAT_INTERVAL_MS = 15000;
|
|
18
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/live/constants.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C,0GAA0G;AAC1G,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,qFAAqF;AACrF,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,wBAAwB,oBAAoB,CAAC;AAE1D;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,QAAS,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Loopback-only default bind host — the adapter refuses non-loopback unless explicitly allowed. */
|
|
2
|
+
export const DEFAULT_LIVE_HOST = "127.0.0.1";
|
|
3
|
+
/** Default TCP port. `0` lets the OS pick a free ephemeral port (read back from the handle's baseUrl). */
|
|
4
|
+
export const DEFAULT_LIVE_PORT = 0;
|
|
5
|
+
/** Default URL prefix under which the adapter mounts `/v1/info` and `/v1/events`. */
|
|
6
|
+
export const DEFAULT_LIVE_BASE_PATH = "/live";
|
|
7
|
+
/**
|
|
8
|
+
* Schema tag surfaced by GET /v1/info so a discovery probe can identify the
|
|
9
|
+
* adapter and its wire version before subscribing to the event stream.
|
|
10
|
+
*/
|
|
11
|
+
export const LIVE_ADAPTER_INFO_SCHEMA = "live-adapter.v1";
|
|
12
|
+
/**
|
|
13
|
+
* Interval between SSE heartbeat comment lines (`: ping\n\n`). Heartbeats keep
|
|
14
|
+
* idle proxies/clients from dropping the connection between runs; the comment
|
|
15
|
+
* form carries no data and is ignored by SSE parsers.
|
|
16
|
+
*/
|
|
17
|
+
export const LIVE_HEARTBEAT_INTERVAL_MS = 15_000;
|
|
18
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/live/constants.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAE7C,0GAA0G;AAC1G,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC,qFAAqF;AACrF,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,iBAAiB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CodedError } from "@mono-agent/agent-contracts";
|
|
2
|
+
export type LiveAdapterErrorCode = "invalid_config" | "unsafe_host" | "start_failed";
|
|
3
|
+
export interface LiveAdapterErrorDetails {
|
|
4
|
+
readonly code?: LiveAdapterErrorCode;
|
|
5
|
+
readonly reason?: string;
|
|
6
|
+
readonly [key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
export declare class LiveAdapterError extends CodedError<LiveAdapterErrorCode> {
|
|
9
|
+
readonly details: LiveAdapterErrorDetails;
|
|
10
|
+
constructor(code: LiveAdapterErrorCode, message: string, details?: LiveAdapterErrorDetails);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/live/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,MAAM,MAAM,oBAAoB,GAC5B,gBAAgB,GAChB,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,oBAAoB,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,qBAAa,gBAAiB,SAAQ,UAAU,CAAC,oBAAoB,CAAC;IACpE,SAAiB,OAAO,EAAE,uBAAuB,CAAC;gBAGhD,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,uBAA4B;CAIxC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/live/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAazD,MAAM,OAAO,gBAAiB,SAAQ,UAAgC;IAGpE,YACE,IAA0B,EAC1B,OAAe,EACf,UAAmC,EAAE;QAErC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { startLiveAdapter } from "./server.js";
|
|
2
|
+
export type { LiveAdapterHandle, LiveAdapterLogger, LiveAdapterOptions, } from "./server.js";
|
|
3
|
+
export { LiveAdapterError } from "./errors.js";
|
|
4
|
+
export type { LiveAdapterErrorCode, LiveAdapterErrorDetails } from "./errors.js";
|
|
5
|
+
export { loadLiveAdapterConfig, redactLiveAdapterConfig, LIVE_CONFIG_FIELDS } from "./config.js";
|
|
6
|
+
export type { LiveAdapterConfig, RedactedLiveAdapterConfig, LoadLiveAdapterConfigInput, } from "./config.js";
|
|
7
|
+
export { DEFAULT_LIVE_BASE_PATH, DEFAULT_LIVE_HOST, DEFAULT_LIVE_PORT, LIVE_ADAPTER_INFO_SCHEMA, LIVE_HEARTBEAT_INTERVAL_MS, } from "./constants.js";
|
|
8
|
+
export { LIVE_EVENT_SCHEMA, createLiveEventBus } from "@mono-agent/agent-contracts";
|
|
9
|
+
export type { CreateLiveEventBusOptions, RunEventBus, RunEventFrame, RunEventSink, } from "@mono-agent/agent-contracts";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/live/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjG,YAAY,EACV,iBAAiB,EACjB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACpF,YAAY,EACV,yBAAyB,EACzB,WAAW,EACX,aAAa,EACb,YAAY,GACb,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { startLiveAdapter } from "./server.js";
|
|
2
|
+
export { LiveAdapterError } from "./errors.js";
|
|
3
|
+
export { loadLiveAdapterConfig, redactLiveAdapterConfig, LIVE_CONFIG_FIELDS } from "./config.js";
|
|
4
|
+
export { DEFAULT_LIVE_BASE_PATH, DEFAULT_LIVE_HOST, DEFAULT_LIVE_PORT, LIVE_ADAPTER_INFO_SCHEMA, LIVE_HEARTBEAT_INTERVAL_MS, } from "./constants.js";
|
|
5
|
+
// Re-export the shared live-event contract + the in-process bus factory (both live
|
|
6
|
+
// in core) so consumers can build/type producers and subscribers from one import.
|
|
7
|
+
export { LIVE_EVENT_SCHEMA, createLiveEventBus } from "@mono-agent/agent-contracts";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/live/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAM/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAMjG,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC;AAExB,mFAAmF;AACnF,kFAAkF;AAClF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type RunEventBus } from "@mono-agent/agent-contracts";
|
|
2
|
+
export interface LiveAdapterLogger {
|
|
3
|
+
debug?(message: string, metadata?: Record<string, unknown>): void;
|
|
4
|
+
info?(message: string, metadata?: Record<string, unknown>): void;
|
|
5
|
+
warn?(message: string, metadata?: Record<string, unknown>): void;
|
|
6
|
+
error?(message: string, metadata?: Record<string, unknown>): void;
|
|
7
|
+
}
|
|
8
|
+
export interface LiveAdapterOptions {
|
|
9
|
+
/** In-process bus the adapter subscribes to and replays. Read-only — never written. */
|
|
10
|
+
readonly bus: RunEventBus;
|
|
11
|
+
readonly host?: string;
|
|
12
|
+
readonly port?: number;
|
|
13
|
+
readonly basePath?: string;
|
|
14
|
+
readonly allowNonLoopback?: boolean;
|
|
15
|
+
/** When set, both routes require `Authorization: Bearer <apiKey>`; a mismatch is a 401. */
|
|
16
|
+
readonly apiKey?: string;
|
|
17
|
+
/** Human label surfaced by GET /v1/info so a discovery probe can name the instance. */
|
|
18
|
+
readonly label?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Invoked when the already-listening HTTP server dies (e.g. a socket-level
|
|
21
|
+
* failure appearing later). The hosting channel driver maps this to its
|
|
22
|
+
* onFailure hook so the channel flips to "failed" instead of silently serving
|
|
23
|
+
* nothing.
|
|
24
|
+
*/
|
|
25
|
+
readonly onServerError?: (reason: string) => void;
|
|
26
|
+
readonly logger?: LiveAdapterLogger;
|
|
27
|
+
}
|
|
28
|
+
export interface LiveAdapterHandle {
|
|
29
|
+
/** SSE root: `http://<host>:<actualPort><basePath>`. `/v1/events` and `/v1/info` hang off it. */
|
|
30
|
+
readonly baseUrl: string;
|
|
31
|
+
/** Tear down every open SSE connection and close the HTTP server. */
|
|
32
|
+
stop(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Start a loopback, read-only SSE server that relays a {@link RunEventBus} to
|
|
36
|
+
* operator surfaces. It observes only: there is no turn-driving endpoint and no
|
|
37
|
+
* reference to a responder.
|
|
38
|
+
*/
|
|
39
|
+
export declare function startLiveAdapter(options: LiveAdapterOptions): Promise<LiveAdapterHandle>;
|
|
40
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/live/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqC,KAAK,WAAW,EAAsB,MAAM,6BAA6B,CAAC;AAwBtH,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAClE,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACjE,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACjE,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACnE;AAED,MAAM,WAAW,kBAAkB;IACjC,uFAAuF;IACvF,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,uFAAuF;IACvF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,iGAAiG;IACjG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AASD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmL9F"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { DEFAULT_RUN_EVENT_MAX_FRAME_BYTES } from "@mono-agent/agent-contracts";
|
|
3
|
+
import { assertSafeBind, bearerTokensEqual, close, hostForUrl, listen, normalizeOptionalString, readAuthorizationBearer, } from "@mono-agent/agent-contracts";
|
|
4
|
+
import express, {} from "express";
|
|
5
|
+
import { DEFAULT_LIVE_BASE_PATH, DEFAULT_LIVE_HOST, DEFAULT_LIVE_PORT, LIVE_ADAPTER_INFO_SCHEMA, LIVE_HEARTBEAT_INTERVAL_MS, } from "./constants.js";
|
|
6
|
+
import { LiveAdapterError } from "./errors.js";
|
|
7
|
+
const MAX_SSE_QUEUE_FRAMES = 1_000;
|
|
8
|
+
const FRAME_ENCODER = new TextEncoder();
|
|
9
|
+
/**
|
|
10
|
+
* Start a loopback, read-only SSE server that relays a {@link RunEventBus} to
|
|
11
|
+
* operator surfaces. It observes only: there is no turn-driving endpoint and no
|
|
12
|
+
* reference to a responder.
|
|
13
|
+
*/
|
|
14
|
+
export async function startLiveAdapter(options) {
|
|
15
|
+
if (options.bus === undefined || typeof options.bus.subscribe !== "function") {
|
|
16
|
+
throw new LiveAdapterError("invalid_config", "startLiveAdapter requires a RunEventBus.");
|
|
17
|
+
}
|
|
18
|
+
const host = options.host ?? DEFAULT_LIVE_HOST;
|
|
19
|
+
const port = options.port ?? DEFAULT_LIVE_PORT;
|
|
20
|
+
const basePath = normalizeBasePath(options.basePath ?? DEFAULT_LIVE_BASE_PATH);
|
|
21
|
+
const apiKey = normalizeOptionalString(options.apiKey);
|
|
22
|
+
const label = normalizeOptionalString(options.label);
|
|
23
|
+
assertSafeBind(host, options.allowNonLoopback === true, (boundHost) => new LiveAdapterError("unsafe_host", "Live adapter refuses to bind a non-loopback host unless allowNonLoopback is true.", { host: boundHost }));
|
|
24
|
+
const app = express();
|
|
25
|
+
const server = createServer(app);
|
|
26
|
+
const infoPath = `${basePath}/v1/info`;
|
|
27
|
+
const eventsPath = `${basePath}/v1/events`;
|
|
28
|
+
const connections = new Set();
|
|
29
|
+
app.get(infoPath, (req, res) => {
|
|
30
|
+
if (!authorize(req, res, apiKey)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
res.status(200).json({
|
|
34
|
+
schema: LIVE_ADAPTER_INFO_SCHEMA,
|
|
35
|
+
pid: process.pid,
|
|
36
|
+
...(label === undefined ? {} : { label }),
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
app.get(eventsPath, (req, res) => {
|
|
40
|
+
if (!authorize(req, res, apiKey)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
handleEvents(res);
|
|
44
|
+
});
|
|
45
|
+
const address = await listen(server, port, host, {
|
|
46
|
+
listenFailed: (reason) => new LiveAdapterError("start_failed", "Live adapter failed to listen.", { reason }),
|
|
47
|
+
noAddress: () => new LiveAdapterError("start_failed", "Live adapter did not receive a TCP address."),
|
|
48
|
+
});
|
|
49
|
+
server.on("error", (error) => {
|
|
50
|
+
options.onServerError?.(errorToMessage(error));
|
|
51
|
+
});
|
|
52
|
+
const baseUrl = `http://${hostForUrl(host)}:${address.port}${basePath}`;
|
|
53
|
+
function handleEvents(res) {
|
|
54
|
+
// SSE handshake. Mirror the openai-api-adapter header set; disable Nagle so
|
|
55
|
+
// each frame flushes immediately, and flush headers before subscribing so
|
|
56
|
+
// the client sees the stream open promptly.
|
|
57
|
+
res.status(200);
|
|
58
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
59
|
+
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
60
|
+
res.setHeader("Connection", "keep-alive");
|
|
61
|
+
res.setHeader("X-Accel-Buffering", "no");
|
|
62
|
+
res.socket?.setNoDelay(true);
|
|
63
|
+
res.flushHeaders();
|
|
64
|
+
const queue = [];
|
|
65
|
+
let draining = false;
|
|
66
|
+
let closed = false;
|
|
67
|
+
let teardown;
|
|
68
|
+
const flush = () => {
|
|
69
|
+
while (!closed && !draining && queue.length > 0) {
|
|
70
|
+
const payload = queue.shift();
|
|
71
|
+
if (payload === undefined) {
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
if (res.writableEnded) {
|
|
75
|
+
closed = true;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const ok = res.write(payload);
|
|
79
|
+
if (!ok) {
|
|
80
|
+
draining = true;
|
|
81
|
+
res.once("drain", () => {
|
|
82
|
+
draining = false;
|
|
83
|
+
flush();
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const closeSlowClient = () => {
|
|
90
|
+
if (closed) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
options.logger?.warn?.("Closing slow live SSE client after queue overflow.", {
|
|
94
|
+
queuedFrames: queue.length,
|
|
95
|
+
maxQueuedFrames: MAX_SSE_QUEUE_FRAMES,
|
|
96
|
+
});
|
|
97
|
+
teardown?.();
|
|
98
|
+
closed = true;
|
|
99
|
+
queue.length = 0;
|
|
100
|
+
if (!res.writableEnded) {
|
|
101
|
+
res.end();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const enqueue = (payload) => {
|
|
105
|
+
if (closed || res.writableEnded) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
queue.push(payload);
|
|
109
|
+
if (queue.length > MAX_SSE_QUEUE_FRAMES) {
|
|
110
|
+
closeSlowClient();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
flush();
|
|
114
|
+
};
|
|
115
|
+
const write = (frame) => {
|
|
116
|
+
const payload = serializeFrame(frame, options.logger);
|
|
117
|
+
if (payload !== undefined) {
|
|
118
|
+
enqueue(payload);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
// Replay the ring buffer (oldest-first) so a late joiner can reconstruct
|
|
122
|
+
// in-flight runs, then stream every subsequent frame the same way.
|
|
123
|
+
for (const frame of options.bus.recentFrames()) {
|
|
124
|
+
write(frame);
|
|
125
|
+
}
|
|
126
|
+
if (closed) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const unsubscribe = options.bus.subscribe(write);
|
|
130
|
+
const heartbeat = setInterval(() => {
|
|
131
|
+
if (closed || draining || res.writableEnded) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
enqueue(": ping\n\n");
|
|
135
|
+
}, LIVE_HEARTBEAT_INTERVAL_MS);
|
|
136
|
+
// Never keep the process alive solely for the heartbeat timer.
|
|
137
|
+
heartbeat.unref?.();
|
|
138
|
+
let torn = false;
|
|
139
|
+
teardown = () => {
|
|
140
|
+
if (torn) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
torn = true;
|
|
144
|
+
closed = true;
|
|
145
|
+
clearInterval(heartbeat);
|
|
146
|
+
unsubscribe();
|
|
147
|
+
queue.length = 0;
|
|
148
|
+
};
|
|
149
|
+
const connection = { res, teardown };
|
|
150
|
+
connections.add(connection);
|
|
151
|
+
res.once("close", () => {
|
|
152
|
+
connections.delete(connection);
|
|
153
|
+
teardown();
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
baseUrl,
|
|
158
|
+
async stop() {
|
|
159
|
+
// SSE connections never end on their own, so `server.close()` would hang
|
|
160
|
+
// waiting for them — tear each down and end the response first.
|
|
161
|
+
for (const connection of [...connections]) {
|
|
162
|
+
connection.teardown();
|
|
163
|
+
if (!connection.res.writableEnded) {
|
|
164
|
+
connection.res.end();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
connections.clear();
|
|
168
|
+
await close(server);
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function authorize(req, res, apiKey) {
|
|
173
|
+
if (apiKey === undefined) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
const presented = readAuthorizationBearer(req.header("authorization"));
|
|
177
|
+
if (presented !== undefined && bearerTokensEqual(presented, apiKey)) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
res.status(401).json({ error: { message: "Invalid API key.", code: "invalid_api_key" } });
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
function errorToMessage(error) {
|
|
184
|
+
if (error instanceof Error && error.message.length > 0) {
|
|
185
|
+
return error.message;
|
|
186
|
+
}
|
|
187
|
+
return String(error);
|
|
188
|
+
}
|
|
189
|
+
function normalizeBasePath(basePath) {
|
|
190
|
+
if (!isLiteralBasePath(basePath)) {
|
|
191
|
+
throw new LiveAdapterError("invalid_config", "basePath must be an absolute literal path made of slash-separated URL path segments.");
|
|
192
|
+
}
|
|
193
|
+
return basePath.length === 1 ? "" : basePath.replace(/\/+$/u, "");
|
|
194
|
+
}
|
|
195
|
+
function serializeFrame(frame, logger) {
|
|
196
|
+
try {
|
|
197
|
+
// JSON.stringify is single-line, so the only newlines are the SSE terminator.
|
|
198
|
+
const json = JSON.stringify(frame);
|
|
199
|
+
if (FRAME_ENCODER.encode(json).length > DEFAULT_RUN_EVENT_MAX_FRAME_BYTES) {
|
|
200
|
+
logger?.warn?.("Dropped oversized live event frame.", {
|
|
201
|
+
maxFrameBytes: DEFAULT_RUN_EVENT_MAX_FRAME_BYTES,
|
|
202
|
+
runId: "runId" in frame ? frame.runId : undefined,
|
|
203
|
+
});
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
return `data: ${json}\n\n`;
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
logger?.warn?.("Dropped unserializable live event frame.", {
|
|
210
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
211
|
+
runId: "runId" in frame ? frame.runId : undefined,
|
|
212
|
+
});
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function isLiteralBasePath(basePath) {
|
|
217
|
+
return basePath === "/" || /^\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*\/?$/u.test(basePath);
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/live/server.ts"],"names":[],"mappings":"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"}
|