@assemblyline-agents/node 0.1.0

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -0
  3. package/dist/adapters.d.ts +17 -0
  4. package/dist/adapters.d.ts.map +1 -0
  5. package/dist/adapters.js +122 -0
  6. package/dist/adapters.js.map +1 -0
  7. package/dist/auth.d.ts +45 -0
  8. package/dist/auth.d.ts.map +1 -0
  9. package/dist/auth.js +196 -0
  10. package/dist/auth.js.map +1 -0
  11. package/dist/direct-conversations-http.d.ts +40 -0
  12. package/dist/direct-conversations-http.d.ts.map +1 -0
  13. package/dist/direct-conversations-http.js +140 -0
  14. package/dist/direct-conversations-http.js.map +1 -0
  15. package/dist/http-io.d.ts +20 -0
  16. package/dist/http-io.d.ts.map +1 -0
  17. package/dist/http-io.js +101 -0
  18. package/dist/http-io.js.map +1 -0
  19. package/dist/index.d.ts +49 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +750 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/lifecycle.d.ts +56 -0
  24. package/dist/lifecycle.d.ts.map +1 -0
  25. package/dist/lifecycle.js +112 -0
  26. package/dist/lifecycle.js.map +1 -0
  27. package/dist/multipart.d.ts +3 -0
  28. package/dist/multipart.d.ts.map +1 -0
  29. package/dist/multipart.js +125 -0
  30. package/dist/multipart.js.map +1 -0
  31. package/dist/provider-resolver.d.ts +17 -0
  32. package/dist/provider-resolver.d.ts.map +1 -0
  33. package/dist/provider-resolver.js +94 -0
  34. package/dist/provider-resolver.js.map +1 -0
  35. package/dist/rate-limit.d.ts +60 -0
  36. package/dist/rate-limit.d.ts.map +1 -0
  37. package/dist/rate-limit.js +98 -0
  38. package/dist/rate-limit.js.map +1 -0
  39. package/dist/route-match.d.ts +21 -0
  40. package/dist/route-match.d.ts.map +1 -0
  41. package/dist/route-match.js +89 -0
  42. package/dist/route-match.js.map +1 -0
  43. package/dist/run-stream-http.d.ts +13 -0
  44. package/dist/run-stream-http.d.ts.map +1 -0
  45. package/dist/run-stream-http.js +145 -0
  46. package/dist/run-stream-http.js.map +1 -0
  47. package/dist/usage-http.d.ts +9 -0
  48. package/dist/usage-http.d.ts.map +1 -0
  49. package/dist/usage-http.js +184 -0
  50. package/dist/usage-http.js.map +1 -0
  51. package/package.json +96 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenEve contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # @assemblyline-agents/node
2
+
3
+ The Node.js host for the Assembly Line runtime.
4
+
5
+ It wires the `@assemblyline-agents/runtime` engine to a Node HTTP server: loading compiled runtime bundles, resolving state/blob/sandbox adapters from provider configuration, routing channel and API requests, enforcing auth and rate-limit policies, streaming run output over HTTP, and managing host lifecycle. Authenticated `GET /usage` exposes filtered records or exact rollups, while `POST /usage/reconcile` imports OpenAI/OpenRouter control totals and retries pending receipts using runtime-held credentials. This is the process that actually serves a deployed Assembly Line agent in Node environments (containers, Fly.io, Railway, bare servers).
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @assemblyline-agents/node
11
+ ```
12
+
13
+ ## Part of Assembly Line
14
+
15
+ This package is part of [Assembly Line](https://github.com/jasonbadeaux/openeve), a vendor-neutral, filesystem-first framework for durable AI agents. See the developer documentation in [docs/developers/](https://github.com/jasonbadeaux/openeve/tree/main/docs/developers) for setup, agent authoring, and deployment guides.
16
+
17
+ ## License
18
+
19
+ MIT
@@ -0,0 +1,17 @@
1
+ import { type BlobAdapter, type ConnectionAuthorizationSessionStore, type ConnectionDefinitionStore, type ConnectionGrantStore, type OpenEveRuntime, type RunTimeline, type RuntimeOptions, type SandboxAdapter, type ScheduleStore, type SkillStore, type StateAdapter } from "@assemblyline-agents/runtime";
2
+ import { type ProviderResolution } from "./provider-resolver.js";
3
+ export declare function loadRunTimeline(runtime: OpenEveRuntime, runId: string): Promise<RunTimeline | undefined>;
4
+ export declare function createConnectionStores(_options: RuntimeOptions, artifactRoot: string, env: NodeJS.ProcessEnv, state: StateAdapter, devMode: boolean): {
5
+ grantStore: ConnectionGrantStore;
6
+ authorizationSessionStore: ConnectionAuthorizationSessionStore;
7
+ };
8
+ export declare function createSelfImprovementStores(artifactRoot: string, env: NodeJS.ProcessEnv, state: StateAdapter): {
9
+ skillStore: SkillStore;
10
+ scheduleStore: ScheduleStore;
11
+ connectionDefinitionStore: ConnectionDefinitionStore;
12
+ };
13
+ export declare function providerResolution(options: RuntimeOptions, artifactRoot: string, env: NodeJS.ProcessEnv): ProviderResolution;
14
+ export declare function createStateAdapter(options: RuntimeOptions, artifactRoot: string, env: NodeJS.ProcessEnv): Promise<StateAdapter>;
15
+ export declare function createBlobAdapter(options: RuntimeOptions, artifactRoot: string, env: NodeJS.ProcessEnv): Promise<BlobAdapter>;
16
+ export declare function createSandboxAdapter(options: RuntimeOptions, artifactRoot: string, env: NodeJS.ProcessEnv): Promise<SandboxAdapter>;
17
+ //# sourceMappingURL=adapters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAEA,OAAO,EASL,KAAK,WAAW,EAChB,KAAK,mCAAmC,EACxC,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,YAAY,EAClB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAKlF,wBAAsB,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAO9G;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,cAAc,EACxB,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,OAAO,GACf;IACD,UAAU,EAAE,oBAAoB,CAAC;IACjC,yBAAyB,EAAE,mCAAmC,CAAC;CAChE,CAeA;AAkBD,wBAAgB,2BAA2B,CACzC,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,KAAK,EAAE,YAAY,GAClB;IACD,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,aAAa,CAAC;IAC7B,yBAAyB,EAAE,yBAAyB,CAAC;CACtD,CAeA;AAUD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,kBAAkB,CAQ5H;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAMrI;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAMnI;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAWzI"}
@@ -0,0 +1,122 @@
1
+ import { join } from "node:path";
2
+ import { adapter, isSensitiveSandboxEnvName } from "@assemblyline-agents/core";
3
+ import { FileConnectionDefinitionStore, FileScheduleStore, FileSkillStore, FileStateAdapter, FileConnectionAuthorizationSessionStore, FileConnectionGrantStore, LocalBlobAdapter, LocalSandboxAdapter } from "@assemblyline-agents/runtime";
4
+ import { resolveProvider } from "./provider-resolver.js";
5
+ const LOCAL_DEV_CONNECTION_STORE_SECRET = "openeve-local-dev-connection-secret";
6
+ const MIN_PRODUCTION_CONNECTION_STORE_SECRET_LENGTH = 32;
7
+ export async function loadRunTimeline(runtime, runId) {
8
+ try {
9
+ return await runtime.replay(runId);
10
+ }
11
+ catch (error) {
12
+ if (error instanceof Error && error.message === `Run not found: ${runId}`)
13
+ return undefined;
14
+ throw error;
15
+ }
16
+ }
17
+ export function createConnectionStores(_options, artifactRoot, env, state, devMode) {
18
+ if (isConnectionGrantStore(state) && isConnectionAuthorizationSessionStore(state)) {
19
+ return {
20
+ grantStore: state,
21
+ authorizationSessionStore: state
22
+ };
23
+ }
24
+ const secret = resolveConnectionStoreSecret(env, devMode);
25
+ return {
26
+ grantStore: new FileConnectionGrantStore(env.OPENEVE_CONNECTION_GRANTS_FILE ?? join(artifactRoot, "connection-grants.enc.json"), secret),
27
+ authorizationSessionStore: new FileConnectionAuthorizationSessionStore(env.OPENEVE_CONNECTION_AUTH_SESSIONS_FILE ?? join(artifactRoot, "connection-auth-sessions.enc.json"), secret)
28
+ };
29
+ }
30
+ function resolveConnectionStoreSecret(env, devMode) {
31
+ const rawSecret = env.OPENEVE_CONNECTION_STORE_SECRET ?? env.OPENEVE_SECRET;
32
+ const secret = rawSecret?.trim();
33
+ if (!secret) {
34
+ if (devMode)
35
+ return LOCAL_DEV_CONNECTION_STORE_SECRET;
36
+ throw new Error("File-backed connection credential stores require OPENEVE_CONNECTION_STORE_SECRET or OPENEVE_SECRET outside dev mode. Use Postgres state or configure a secret with at least 32 characters.");
37
+ }
38
+ if (!devMode && secret === LOCAL_DEV_CONNECTION_STORE_SECRET) {
39
+ throw new Error("File-backed connection credential stores cannot use the local development secret outside dev mode.");
40
+ }
41
+ if (!devMode && secret.length < MIN_PRODUCTION_CONNECTION_STORE_SECRET_LENGTH) {
42
+ throw new Error("File-backed connection credential store secrets must be at least 32 characters outside dev mode.");
43
+ }
44
+ return secret;
45
+ }
46
+ export function createSelfImprovementStores(artifactRoot, env, state) {
47
+ // Postgres exposes durable store instances sharing its client; otherwise fall
48
+ // back to local JSON-file-backed stores under the artifact root.
49
+ const provider = state;
50
+ return {
51
+ skillStore: provider.skillStore ?? new FileSkillStore(env.OPENEVE_SKILLS_FILE ?? join(artifactRoot, "skills-store.json")),
52
+ scheduleStore: provider.scheduleStore ?? new FileScheduleStore(env.OPENEVE_SCHEDULES_FILE ?? join(artifactRoot, "dynamic-schedules.json")),
53
+ connectionDefinitionStore: provider.connectionDefinitionStore ??
54
+ new FileConnectionDefinitionStore(env.OPENEVE_CONNECTION_DEFINITIONS_FILE ?? join(artifactRoot, "connection-definitions.json"))
55
+ };
56
+ }
57
+ function isConnectionGrantStore(value) {
58
+ return Boolean(value && typeof value === "object" && "getGrant" in value && "saveGrant" in value && "deleteGrant" in value);
59
+ }
60
+ function isConnectionAuthorizationSessionStore(value) {
61
+ return Boolean(value && typeof value === "object" && "getSessionByState" in value && "findPendingSession" in value);
62
+ }
63
+ export function providerResolution(options, artifactRoot, env) {
64
+ return {
65
+ env,
66
+ fetch: options.fetch ?? fetch,
67
+ manifest: options.manifest,
68
+ artifactRoot,
69
+ devMode: options.devMode === true
70
+ };
71
+ }
72
+ export async function createStateAdapter(options, artifactRoot, env) {
73
+ const definition = options.manifest.gateway.state ?? adapter("local");
74
+ if (definition.kind === "local") {
75
+ return new FileStateAdapter(env.OPENEVE_STATE_FILE ?? join(artifactRoot, "runtime-state.json"));
76
+ }
77
+ return resolveProvider("state", definition, providerResolution(options, artifactRoot, env));
78
+ }
79
+ export async function createBlobAdapter(options, artifactRoot, env) {
80
+ const definition = options.manifest.gateway.blob ?? adapter("local");
81
+ if (definition.kind === "local") {
82
+ return new LocalBlobAdapter(env.OPENEVE_BLOB_ROOT ?? join(artifactRoot, "blobs"));
83
+ }
84
+ return resolveProvider("blob", definition, providerResolution(options, artifactRoot, env));
85
+ }
86
+ export async function createSandboxAdapter(options, artifactRoot, env) {
87
+ const definition = options.manifest.gateway.sandbox ?? adapter("local");
88
+ if (definition.kind === "local") {
89
+ if (options.devMode !== true && env.OPENEVE_ALLOW_LOCAL_SANDBOX_IN_PRODUCTION !== "true") {
90
+ throw new Error("Production OpenEve Node runtime refuses the local sandbox. Configure a network-confined sandbox adapter or set OPENEVE_ALLOW_LOCAL_SANDBOX_IN_PRODUCTION=true to acknowledge the risk.");
91
+ }
92
+ return new LocalSandboxAdapter(env.OPENEVE_SANDBOX_ROOT ?? join(artifactRoot, "sandbox"));
93
+ }
94
+ const sandbox = options.manifest.sandboxes.find((candidate) => candidate.adapter === definition.kind) ?? options.manifest.sandboxes[0];
95
+ const sandboxOptions = sandboxRuntimeOptions(sandbox, env);
96
+ return resolveProvider("sandbox", definition, providerResolution(options, artifactRoot, env), sandboxOptions);
97
+ }
98
+ function collectEnv(env, names) {
99
+ const out = {};
100
+ for (const name of names) {
101
+ const value = env[name];
102
+ if (value !== undefined)
103
+ out[name] = value;
104
+ }
105
+ return out;
106
+ }
107
+ function sandboxRuntimeOptions(sandbox, env) {
108
+ const options = {};
109
+ if (sandbox?.image)
110
+ options.image = sandbox.image;
111
+ if (sandbox?.workingDirectory)
112
+ options.workingDirectory = sandbox.workingDirectory;
113
+ const passthroughEnv = collectEnv(env, sandbox?.env ?? []);
114
+ const sensitive = Object.keys(passthroughEnv).filter(isSensitiveSandboxEnvName);
115
+ if (sensitive.length > 0) {
116
+ throw new Error(`Refusing host/control-plane secrets in global sandbox env: ${sensitive.join(", ")}.`);
117
+ }
118
+ if (Object.keys(passthroughEnv).length > 0)
119
+ options.env = passthroughEnv;
120
+ return options;
121
+ }
122
+ //# sourceMappingURL=adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import { type JsonValue } from "@assemblyline-agents/core";
3
+ import { type OpenEveRuntime } from "@assemblyline-agents/runtime";
4
+ import type { NodeRuntimeServerOptions } from "./index.js";
5
+ import type { IngressRateLimitClass, ResolvedIngressRateLimit } from "./rate-limit.js";
6
+ export type RuntimeRouteClass = "public-health" | "provider-channel" | "scheduler" | "connection-callback" | "admin-read" | "run-create" | "run-resume" | "run-control" | "agent-control";
7
+ export interface RuntimeAuthRequest {
8
+ routeClass: RuntimeRouteClass;
9
+ method: string;
10
+ path: string;
11
+ channel?: string;
12
+ headers: Record<string, string>;
13
+ }
14
+ export type RuntimeAuthDecision = {
15
+ allowed: true;
16
+ trusted?: boolean;
17
+ } | {
18
+ allowed: false;
19
+ status?: 401 | 403;
20
+ reason?: string;
21
+ };
22
+ type RuntimeAllowedAuthDecision = Extract<RuntimeAuthDecision, {
23
+ allowed: true;
24
+ }>;
25
+ export interface RuntimeAuthPolicy {
26
+ authorize(request: RuntimeAuthRequest): RuntimeAuthDecision | Promise<RuntimeAuthDecision>;
27
+ }
28
+ export declare function logHttpRequest(runtime: OpenEveRuntime, request: IncomingMessage, response: ServerResponse, startedAt: number, channel?: string): void;
29
+ export declare function validateRuntimeHttpSecurity(runtime: OpenEveRuntime, options: NodeRuntimeServerOptions): void;
30
+ /** Applies the resolved ingress rate limit after auth; 429 + Retry-After on deny. */
31
+ export declare function rateLimitOrSend(request: IncomingMessage, response: ServerResponse, rateLimit: ResolvedIngressRateLimit | undefined, routeClass: IngressRateLimitClass, path: string, channel?: string): Promise<boolean>;
32
+ export declare function authorizeOrSend(request: IncomingMessage, response: ServerResponse, runtime: OpenEveRuntime, options: NodeRuntimeServerOptions, routeClass: RuntimeRouteClass, path: string, channel?: string): Promise<RuntimeAllowedAuthDecision | undefined>;
33
+ export declare function apiRunCreationEnabled(runtime: OpenEveRuntime, options: NodeRuntimeServerOptions): boolean;
34
+ /**
35
+ * Gates the POST /runs `eval` block (tool stubs, approval auto-resolve,
36
+ * record-only delivery). Separate from apiRunCreationEnabled because
37
+ * OPENEVE_ENABLE_API_RUNS is a documented production setting; stubbed runs
38
+ * need their own opt-in. Advertised as the `eval-runs` /healthz capability.
39
+ */
40
+ export declare function evalRunsEnabled(runtime: OpenEveRuntime, options: NodeRuntimeServerOptions): boolean;
41
+ export declare function stringBodyValue(value: JsonValue | undefined): string | undefined;
42
+ export declare function numberBodyValue(value: JsonValue | undefined): number | undefined;
43
+ export declare function numberQueryValue(value: string | null): number | undefined;
44
+ export {};
45
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAA4E,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACrI,OAAO,EAA8C,KAAK,cAAc,EAAuB,MAAM,8BAA8B,CAAC;AAEpI,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAA2B,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhH,MAAM,MAAM,iBAAiB,GACzB,eAAe,GACf,kBAAkB,GAClB,WAAW,GACX,qBAAqB,GACrB,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,iBAAiB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACpC;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,KAAK,0BAA0B,GAAG,OAAO,CAAC,mBAAmB,EAAE;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAElF,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,OAAO,EAAE,kBAAkB,GAAG,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;CAC5F;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAaN;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAO5G;AAYD,qFAAqF;AACrF,wBAAsB,eAAe,CACnC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,wBAAwB,GAAG,SAAS,EAC/C,UAAU,EAAE,qBAAqB,EACjC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,wBAAwB,EACjC,UAAU,EAAE,iBAAiB,EAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC,CAMjD;AAmFD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAKzG;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAKnG;AAaD,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEhF;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEhF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAIzE"}
package/dist/auth.js ADDED
@@ -0,0 +1,196 @@
1
+ import { LEGACY_SCHEDULER_SECRET_HEADER, SCHEDULER_SECRET_HEADER } from "@assemblyline-agents/core";
2
+ import { constantTimeSecretEqual, retryAfterSeconds } from "@assemblyline-agents/runtime";
3
+ import { headerValue, normalizeHeaders, send } from "./http-io.js";
4
+ export function logHttpRequest(runtime, request, response, startedAt, channel) {
5
+ const url = request.url ? new URL(request.url, "http://localhost") : undefined;
6
+ const entry = {
7
+ type: "http.request",
8
+ method: request.method ?? "",
9
+ path: url?.pathname ?? "",
10
+ status: response.statusCode,
11
+ durationMs: Date.now() - startedAt
12
+ };
13
+ if (channel)
14
+ entry.channel = channel;
15
+ const requestId = headerValue(request.headers["x-railway-request-id"] ?? request.headers["x-request-id"]);
16
+ if (requestId)
17
+ entry.requestId = requestId;
18
+ runtime.logger.info("http request", entry);
19
+ }
20
+ export function validateRuntimeHttpSecurity(runtime, options) {
21
+ if (options.devMode === true)
22
+ return;
23
+ if (options.auth || adminToken(runtime, options)) {
24
+ logRuntimeHttpSecurity(runtime, options);
25
+ return;
26
+ }
27
+ throw new Error("Production OpenEve Node runtime requires OPENEVE_ADMIN_TOKEN or a host-provided auth policy to protect control-plane routes.");
28
+ }
29
+ function logRuntimeHttpSecurity(runtime, options) {
30
+ const entry = {
31
+ type: "openeve.security",
32
+ controlPlane: "authenticated",
33
+ apiRuns: apiRunCreationEnabled(runtime, options) ? "enabled" : "disabled",
34
+ adminAuth: options.auth ? "custom-policy" : "bearer-token"
35
+ };
36
+ runtime.logger.info("runtime http security", entry);
37
+ }
38
+ /** Applies the resolved ingress rate limit after auth; 429 + Retry-After on deny. */
39
+ export async function rateLimitOrSend(request, response, rateLimit, routeClass, path, channel) {
40
+ if (!rateLimit)
41
+ return true;
42
+ const limitRequest = {
43
+ routeClass,
44
+ method: request.method ?? "",
45
+ path,
46
+ headers: normalizeHeaders(request.headers)
47
+ };
48
+ if (channel)
49
+ limitRequest.channel = channel;
50
+ const remoteAddress = request.socket?.remoteAddress;
51
+ if (remoteAddress)
52
+ limitRequest.remoteAddress = remoteAddress;
53
+ const decision = await rateLimit.check(limitRequest);
54
+ if (decision.allowed)
55
+ return true;
56
+ send(response, 429, { error: "Rate limited." }, {
57
+ "retry-after": String(retryAfterSeconds(decision.retryAfterMs))
58
+ });
59
+ return false;
60
+ }
61
+ export async function authorizeOrSend(request, response, runtime, options, routeClass, path, channel) {
62
+ const decision = await authorizeRuntimeRoute(request, runtime, options, routeClass, path, channel);
63
+ if (decision.allowed)
64
+ return decision;
65
+ const status = decision.status ?? 403;
66
+ send(response, status, { error: status === 401 ? "Unauthorized." : "Forbidden." });
67
+ return undefined;
68
+ }
69
+ async function authorizeRuntimeRoute(request, runtime, options, routeClass, path, channel) {
70
+ const method = request.method ?? "";
71
+ const authRequest = {
72
+ routeClass,
73
+ method,
74
+ path,
75
+ headers: normalizeHeaders(request.headers)
76
+ };
77
+ if (channel)
78
+ authRequest.channel = channel;
79
+ if (options.auth) {
80
+ const decision = await options.auth.authorize(authRequest);
81
+ return decision.allowed ? { ...decision, trusted: true } : decision;
82
+ }
83
+ if (routeClass === "public-health" || routeClass === "connection-callback")
84
+ return { allowed: true };
85
+ if (routeClass === "provider-channel") {
86
+ if (options.devMode === true)
87
+ return { allowed: true, trusted: true };
88
+ if (isPublicProviderChannel(runtime, channel))
89
+ return { allowed: true };
90
+ return authorizeBearerRequest(request, runtime, options);
91
+ }
92
+ if (routeClass === "scheduler") {
93
+ return authorizeSchedulerRequest(request, runtime, options)
94
+ ? { allowed: true }
95
+ : { allowed: false, status: 403, reason: "scheduler_unauthorized" };
96
+ }
97
+ if (options.devMode === true)
98
+ return { allowed: true, trusted: true };
99
+ return authorizeBearerRequest(request, runtime, options);
100
+ }
101
+ function authorizeBearerRequest(request, runtime, options) {
102
+ const token = adminToken(runtime, options);
103
+ if (!token)
104
+ return { allowed: false, status: 401, reason: "admin_auth_required" };
105
+ const authorization = headerValue(request.headers.authorization);
106
+ if (!authorization.startsWith("Bearer "))
107
+ return { allowed: false, status: 401, reason: "admin_auth_required" };
108
+ const candidate = authorization.slice("Bearer ".length).trim();
109
+ return constantTimeSecretEqual(candidate, token)
110
+ ? { allowed: true, trusted: true }
111
+ : { allowed: false, status: 403, reason: "admin_auth_invalid" };
112
+ }
113
+ function isPublicProviderChannel(runtime, channelName) {
114
+ if (!channelName)
115
+ return false;
116
+ const channel = runtime.manifest.channels.find((candidate) => candidate.name === channelName);
117
+ const provider = channel ? publicChannelProvider(channel) : "";
118
+ return provider === "slack" ||
119
+ provider === "discord" ||
120
+ provider === "telegram" ||
121
+ provider === "teams" ||
122
+ provider === "photon";
123
+ }
124
+ function publicChannelProvider(channel) {
125
+ const metadataProvider = typeof channel.metadata?.provider === "string" ? channel.metadata.provider : undefined;
126
+ if (metadataProvider === "photon-spectrum")
127
+ return "photon";
128
+ if (metadataProvider === "microsoft-teams")
129
+ return "teams";
130
+ if (metadataProvider)
131
+ return metadataProvider;
132
+ const env = new Set(channel.requiredEnv);
133
+ if (env.has("SLACK_SIGNING_SECRET") || env.has("SLACK_BOT_TOKEN"))
134
+ return "slack";
135
+ if (env.has("DISCORD_PUBLIC_KEY") || env.has("DISCORD_BOT_TOKEN"))
136
+ return "discord";
137
+ if (env.has("TELEGRAM_BOT_TOKEN"))
138
+ return "telegram";
139
+ if (env.has("MICROSOFT_APP_ID") && env.has("MICROSOFT_APP_PASSWORD"))
140
+ return "teams";
141
+ if (env.has("PHOTON_TRANSPORT_URL") || env.has("PHOTON_BRIDGE_TOKEN"))
142
+ return "photon";
143
+ return undefined;
144
+ }
145
+ function adminToken(runtime, options) {
146
+ const env = options.env ?? runtime.env ?? process.env;
147
+ const token = env.OPENEVE_ADMIN_TOKEN?.trim();
148
+ return token ? token : undefined;
149
+ }
150
+ export function apiRunCreationEnabled(runtime, options) {
151
+ if (options.allowApiRuns !== undefined)
152
+ return options.allowApiRuns;
153
+ if (options.devMode === true)
154
+ return true;
155
+ const env = options.env ?? runtime.env ?? process.env;
156
+ return env.OPENEVE_ENABLE_API_RUNS === "true" || env.OPENEVE_ENABLE_API_RUNS === "1";
157
+ }
158
+ /**
159
+ * Gates the POST /runs `eval` block (tool stubs, approval auto-resolve,
160
+ * record-only delivery). Separate from apiRunCreationEnabled because
161
+ * OPENEVE_ENABLE_API_RUNS is a documented production setting; stubbed runs
162
+ * need their own opt-in. Advertised as the `eval-runs` /healthz capability.
163
+ */
164
+ export function evalRunsEnabled(runtime, options) {
165
+ if (options.allowEvalRuns !== undefined)
166
+ return options.allowEvalRuns;
167
+ if (options.devMode === true)
168
+ return true;
169
+ const env = options.env ?? runtime.env ?? process.env;
170
+ return env.OPENEVE_ENABLE_EVAL_RUNS === "true" || env.OPENEVE_ENABLE_EVAL_RUNS === "1";
171
+ }
172
+ function authorizeSchedulerRequest(request, runtime, options) {
173
+ const env = options.env ?? runtime.env ?? process.env;
174
+ const secret = env.OPENEVE_SCHEDULER_SECRET;
175
+ if (!secret)
176
+ return options.devMode === true;
177
+ const headerSecret = headerValue(request.headers[SCHEDULER_SECRET_HEADER])
178
+ || headerValue(request.headers[LEGACY_SCHEDULER_SECRET_HEADER]);
179
+ if (headerSecret && constantTimeSecretEqual(headerSecret, secret))
180
+ return true;
181
+ const authorization = headerValue(request.headers.authorization);
182
+ return Boolean(authorization) && constantTimeSecretEqual(authorization, `Bearer ${secret}`);
183
+ }
184
+ export function stringBodyValue(value) {
185
+ return typeof value === "string" && value.length > 0 ? value : undefined;
186
+ }
187
+ export function numberBodyValue(value) {
188
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
189
+ }
190
+ export function numberQueryValue(value) {
191
+ if (!value)
192
+ return undefined;
193
+ const parsed = Number(value);
194
+ return Number.isFinite(parsed) ? parsed : undefined;
195
+ }
196
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,uBAAuB,EAAmC,MAAM,2BAA2B,CAAC;AACrI,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAA4C,MAAM,8BAA8B,CAAC;AACpI,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAiCnE,MAAM,UAAU,cAAc,CAC5B,OAAuB,EACvB,OAAwB,EACxB,QAAwB,EACxB,SAAiB,EACjB,OAAgB;IAEhB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/E,MAAM,KAAK,GAAe;QACxB,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;QAC5B,IAAI,EAAE,GAAG,EAAE,QAAQ,IAAI,EAAE;QACzB,MAAM,EAAE,QAAQ,CAAC,UAAU;QAC3B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;KACnC,CAAC;IACF,IAAI,OAAO;QAAE,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;IACrC,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;IAC1G,IAAI,SAAS;QAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;IAC3C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,OAAuB,EAAE,OAAiC;IACpG,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI;QAAE,OAAO;IACrC,IAAI,OAAO,CAAC,IAAI,IAAI,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;QACjD,sBAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,8HAA8H,CAAC,CAAC;AAClJ,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAuB,EAAE,OAAiC;IACxF,MAAM,KAAK,GAAe;QACxB,IAAI,EAAE,kBAAkB;QACxB,YAAY,EAAE,eAAe;QAC7B,OAAO,EAAE,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU;QACzE,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,cAAc;KAC3D,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;AACtD,CAAC;AAED,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAwB,EACxB,QAAwB,EACxB,SAA+C,EAC/C,UAAiC,EACjC,IAAY,EACZ,OAAgB;IAEhB,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,YAAY,GAA4B;QAC5C,UAAU;QACV,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;QAC5B,IAAI;QACJ,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;KAC3C,CAAC;IACF,IAAI,OAAO;QAAE,YAAY,CAAC,OAAO,GAAG,OAAO,CAAC;IAC5C,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,aAAa,CAAC;IACpD,IAAI,aAAa;QAAE,YAAY,CAAC,aAAa,GAAG,aAAa,CAAC;IAC9D,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACrD,IAAI,QAAQ,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAClC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE;QAC9C,aAAa,EAAE,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;KAChE,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAwB,EACxB,QAAwB,EACxB,OAAuB,EACvB,OAAiC,EACjC,UAA6B,EAC7B,IAAY,EACZ,OAAgB;IAEhB,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACnG,IAAI,QAAQ,CAAC,OAAO;QAAE,OAAO,QAAQ,CAAC;IACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAC;IACtC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;IACnF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,OAAwB,EACxB,OAAuB,EACvB,OAAiC,EACjC,UAA6B,EAC7B,IAAY,EACZ,OAAgB;IAEhB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;IACpC,MAAM,WAAW,GAAuB;QACtC,UAAU;QACV,MAAM;QACN,IAAI;QACJ,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;KAC3C,CAAC;IACF,IAAI,OAAO;QAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC3D,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IACtE,CAAC;IACD,IAAI,UAAU,KAAK,eAAe,IAAI,UAAU,KAAK,qBAAqB;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACrG,IAAI,UAAU,KAAK,kBAAkB,EAAE,CAAC;QACtC,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACtE,IAAI,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACxE,OAAO,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,UAAU,KAAK,WAAW,EAAE,CAAC;QAC/B,OAAO,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;YACzD,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE;YACnB,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IACxE,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACtE,OAAO,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,sBAAsB,CAC7B,OAAwB,EACxB,OAAuB,EACvB,OAAiC;IAEjC,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAClF,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACjE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChH,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,OAAO,uBAAuB,CAAC,SAAS,EAAE,KAAK,CAAC;QAC9C,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;QAClC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;AACpE,CAAC;AAED,SAAS,uBAAuB,CAAC,OAAuB,EAAE,WAA+B;IACvF,IAAI,CAAC,WAAW;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;IAC9F,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/D,OAAO,QAAQ,KAAK,OAAO;QACzB,QAAQ,KAAK,SAAS;QACtB,QAAQ,KAAK,UAAU;QACvB,QAAQ,KAAK,OAAO;QACpB,QAAQ,KAAK,QAAQ,CAAC;AAC1B,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAuD;IACpF,MAAM,gBAAgB,GAAG,OAAO,OAAO,CAAC,QAAQ,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IAChH,IAAI,gBAAgB,KAAK,iBAAiB;QAAE,OAAO,QAAQ,CAAC;IAC5D,IAAI,gBAAgB,KAAK,iBAAiB;QAAE,OAAO,OAAO,CAAC;IAC3D,IAAI,gBAAgB;QAAE,OAAO,gBAAgB,CAAC;IAC9C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACzC,IAAI,GAAG,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAAE,OAAO,OAAO,CAAC;IAClF,IAAI,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAAE,OAAO,SAAS,CAAC;IACpF,IAAI,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAAE,OAAO,UAAU,CAAC;IACrD,IAAI,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,wBAAwB,CAAC;QAAE,OAAO,OAAO,CAAC;IACrF,IAAI,GAAG,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,qBAAqB,CAAC;QAAE,OAAO,QAAQ,CAAC;IACvF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,UAAU,CAAC,OAAuB,EAAE,OAAiC;IAC5E,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACtD,MAAM,KAAK,GAAG,GAAG,CAAC,mBAAmB,EAAE,IAAI,EAAE,CAAC;IAC9C,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAuB,EAAE,OAAiC;IAC9F,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,YAAY,CAAC;IACpE,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACtD,OAAO,GAAG,CAAC,uBAAuB,KAAK,MAAM,IAAI,GAAG,CAAC,uBAAuB,KAAK,GAAG,CAAC;AACvF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,OAAuB,EAAE,OAAiC;IACxF,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,aAAa,CAAC;IACtE,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACtD,OAAO,GAAG,CAAC,wBAAwB,KAAK,MAAM,IAAI,GAAG,CAAC,wBAAwB,KAAK,GAAG,CAAC;AACzF,CAAC;AAED,SAAS,yBAAyB,CAAC,OAAwB,EAAE,OAAuB,EAAE,OAAiC;IACrH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACtD,MAAM,MAAM,GAAG,GAAG,CAAC,wBAAwB,CAAC;IAC5C,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC;IAC7C,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;WACrE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC,CAAC;IAClE,IAAI,YAAY,IAAI,uBAAuB,CAAC,YAAY,EAAE,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/E,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACjE,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,uBAAuB,CAAC,aAAa,EAAE,UAAU,MAAM,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAA4B;IAC1D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAA4B;IAC1D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAoB;IACnD,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC"}
@@ -0,0 +1,40 @@
1
+ import type { AgentManifest, JsonObject } from "@assemblyline-agents/core";
2
+ import type { ChannelTurn, ConversationCursor, ConversationRecord, MessageCursor } from "@assemblyline-agents/runtime";
3
+ export declare const DIRECT_CHANNEL = "direct";
4
+ export type ConversationHttpRoute = {
5
+ kind: "collection";
6
+ } | {
7
+ kind: "record";
8
+ conversationId: string;
9
+ } | {
10
+ kind: "messages";
11
+ conversationId: string;
12
+ } | {
13
+ kind: "turns";
14
+ conversationId: string;
15
+ };
16
+ export declare function parseConversationHttpRoute(pathname: string): ConversationHttpRoute | undefined;
17
+ export declare function directAgentScope(manifest: AgentManifest): string;
18
+ export declare function conversationBelongsToAgent(conversation: ConversationRecord, agentScope: string): boolean;
19
+ export declare function encodeConversationCursor(conversation: ConversationRecord): string;
20
+ export declare function decodeConversationCursor(value: string | null): ConversationCursor | undefined;
21
+ export declare function encodeMessageCursor(message: {
22
+ createdAt: string;
23
+ id: string;
24
+ }): string;
25
+ export declare function decodeMessageCursor(value: string | null): MessageCursor | undefined;
26
+ export declare function directTurnFromBody(input: {
27
+ conversationId: string;
28
+ body: JsonObject;
29
+ idempotencyKey?: string;
30
+ }): {
31
+ turn: ChannelTurn;
32
+ stream: boolean;
33
+ approve: boolean;
34
+ };
35
+ export declare function directConversationPatch(body: JsonObject): {
36
+ title?: string | null;
37
+ archivedAt?: string | null;
38
+ metadata?: JsonObject;
39
+ };
40
+ //# sourceMappingURL=direct-conversations-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct-conversations-http.d.ts","sourceRoot":"","sources":["../src/direct-conversations-http.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACd,MAAM,8BAA8B,CAAC;AAEtC,eAAO,MAAM,cAAc,WAAW,CAAC;AAEvC,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAS9F;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,CAGhE;AAED,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAExG;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,kBAAkB,GAAG,MAAM,CAEjF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,kBAAkB,GAAG,SAAS,CAI7F;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEtF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,GAAG,SAAS,CAInF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA4B3D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,UAAU,GAAG;IACzD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,UAAU,CAAC;CACvB,CAeA"}
@@ -0,0 +1,140 @@
1
+ import { randomUUID } from "node:crypto";
2
+ export const DIRECT_CHANNEL = "direct";
3
+ export function parseConversationHttpRoute(pathname) {
4
+ if (pathname === "/conversations")
5
+ return { kind: "collection" };
6
+ const match = pathname.match(/^\/conversations\/([^/]+)(?:\/(messages|turns))?$/u);
7
+ if (!match)
8
+ return undefined;
9
+ const conversationId = decodeURIComponent(match[1] ?? "");
10
+ if (!conversationId || conversationId.length > 200)
11
+ return undefined;
12
+ if (match[2] === "messages")
13
+ return { kind: "messages", conversationId };
14
+ if (match[2] === "turns")
15
+ return { kind: "turns", conversationId };
16
+ return { kind: "record", conversationId };
17
+ }
18
+ export function directAgentScope(manifest) {
19
+ const id = typeof manifest.agent.id === "string" ? manifest.agent.id.trim() : "";
20
+ return id ? `agent:${id}` : manifest.agentRevision;
21
+ }
22
+ export function conversationBelongsToAgent(conversation, agentScope) {
23
+ return (conversation.agentScope ?? conversation.agentRevision) === agentScope;
24
+ }
25
+ export function encodeConversationCursor(conversation) {
26
+ return encodeCursor({ updatedAt: conversation.updatedAt, id: conversation.id });
27
+ }
28
+ export function decodeConversationCursor(value) {
29
+ const decoded = decodeCursor(value);
30
+ if (!decoded || typeof decoded.updatedAt !== "string" || typeof decoded.id !== "string")
31
+ return undefined;
32
+ return { updatedAt: decoded.updatedAt, id: decoded.id };
33
+ }
34
+ export function encodeMessageCursor(message) {
35
+ return encodeCursor({ createdAt: message.createdAt, id: message.id });
36
+ }
37
+ export function decodeMessageCursor(value) {
38
+ const decoded = decodeCursor(value);
39
+ if (!decoded || typeof decoded.createdAt !== "string" || typeof decoded.id !== "string")
40
+ return undefined;
41
+ return { createdAt: decoded.createdAt, id: decoded.id };
42
+ }
43
+ export function directTurnFromBody(input) {
44
+ const metadata = jsonObjectField(input.body.metadata);
45
+ const title = stringField(input.body.title)?.slice(0, 160);
46
+ if (title)
47
+ metadata.conversationTitle = title;
48
+ metadata.transport = "http";
49
+ const attachments = arrayField(input.body.attachments);
50
+ const files = arrayField(input.body.__files);
51
+ attachments.push(...files);
52
+ const eventId = stringField(input.body.eventId) ?? input.idempotencyKey ?? randomUUID();
53
+ const turn = {
54
+ eventId,
55
+ channel: DIRECT_CHANNEL,
56
+ conversationId: input.conversationId,
57
+ message: stringField(input.body.message) ?? "",
58
+ attachments,
59
+ delivery: {},
60
+ metadata
61
+ };
62
+ const userId = stringField(input.body.userId);
63
+ const model = stringField(input.body.model);
64
+ if (userId)
65
+ turn.userId = userId;
66
+ if (model)
67
+ turn.model = model;
68
+ return {
69
+ turn,
70
+ stream: booleanField(input.body.stream),
71
+ approve: booleanField(input.body.approve)
72
+ };
73
+ }
74
+ export function directConversationPatch(body) {
75
+ const patch = {};
76
+ if (body.title === null)
77
+ patch.title = null;
78
+ else {
79
+ const title = stringField(body.title);
80
+ if (title)
81
+ patch.title = title.slice(0, 160);
82
+ }
83
+ if (typeof body.archived === "boolean")
84
+ patch.archivedAt = body.archived ? new Date().toISOString() : null;
85
+ const metadata = jsonObjectField(body.metadata);
86
+ if (Object.keys(metadata).length > 0)
87
+ patch.metadata = metadata;
88
+ return patch;
89
+ }
90
+ function encodeCursor(value) {
91
+ return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
92
+ }
93
+ function decodeCursor(value) {
94
+ if (!value)
95
+ return undefined;
96
+ try {
97
+ const parsed = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
98
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
99
+ }
100
+ catch {
101
+ return undefined;
102
+ }
103
+ }
104
+ function stringField(value) {
105
+ if (typeof value !== "string")
106
+ return undefined;
107
+ const trimmed = value.trim();
108
+ return trimmed || undefined;
109
+ }
110
+ function booleanField(value) {
111
+ return value === true || value === "true" || value === "1";
112
+ }
113
+ function jsonObjectField(value) {
114
+ if (value && typeof value === "object" && !Array.isArray(value))
115
+ return { ...value };
116
+ if (typeof value !== "string" || !value.trim())
117
+ return {};
118
+ try {
119
+ const parsed = JSON.parse(value);
120
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
121
+ }
122
+ catch {
123
+ return {};
124
+ }
125
+ }
126
+ function arrayField(value) {
127
+ let candidate = value;
128
+ if (typeof candidate === "string" && candidate.trim()) {
129
+ try {
130
+ candidate = JSON.parse(candidate);
131
+ }
132
+ catch {
133
+ return [];
134
+ }
135
+ }
136
+ if (!Array.isArray(candidate))
137
+ return [];
138
+ return candidate.filter((item) => Boolean(item && typeof item === "object" && !Array.isArray(item)));
139
+ }
140
+ //# sourceMappingURL=direct-conversations-http.js.map