@agentic-surfaces/server 0.1.17 → 0.1.19

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.
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>agentic-surfaces — workflow editor</title>
7
- <script type="module" crossorigin src="/assets/index-DM7JIMkr.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index--mzjNaL0.css">
7
+ <script type="module" crossorigin src="/assets/index-aoHYCL_u.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-6vZGwRHS.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/dist/http.d.ts CHANGED
@@ -16,11 +16,11 @@ export interface ServerOptions {
16
16
  workflows?: Workflow[];
17
17
  observer: StreamingObserver;
18
18
  /**
19
- * Trigger a workflow run by name (POST /api/run). Wired by the CLI to the
20
- * engine; events stream back via the observer. When absent, /api/run is 405
21
- * (the editor renders read-only).
19
+ * Trigger a workflow run by name + optional trigger payload (POST /api/run). A payload is
20
+ * needed to run a `trigger.command` sub-workflow directly (e.g. `{ key: "PD-109" }`). Events
21
+ * stream back via the observer. When absent, /api/run is 405 (the editor renders read-only).
22
22
  */
23
- onRun?: (name: string) => void | Promise<unknown>;
23
+ onRun?: (name: string, payload?: unknown) => void | Promise<unknown>;
24
24
  /** Project-level config surfaced at GET /api/config (so the UI shows effective agent defaults + version). */
25
25
  config?: {
26
26
  dryRun?: boolean;
@@ -32,6 +32,17 @@ export interface ServerOptions {
32
32
  };
33
33
  /** File-based agent definitions, surfaced at GET /api/agents (for the node detail view). */
34
34
  agents?: AgentDefinition[];
35
+ /** The engine cache, surfaced at GET/DELETE /api/cache so the dashboard can inspect + clear seen-state. */
36
+ cache?: {
37
+ entries(): {
38
+ seen: string[];
39
+ cursors: Array<{
40
+ key: string;
41
+ value: string;
42
+ }>;
43
+ };
44
+ forget(key: string): void;
45
+ };
35
46
  }
36
47
  /** Build an http.Server that serves the workflow-engine API and optional static files. */
37
48
  export declare function createServer(opts: ServerOptions): http.Server;
package/dist/http.js CHANGED
@@ -26,7 +26,7 @@ function writeEvent(res, event) {
26
26
  }
27
27
  /** Build an http.Server that serves the workflow-engine API and optional static files. */
28
28
  export function createServer(opts) {
29
- const { observer, workflows = [], staticDir, onRun, config, agents = [] } = opts;
29
+ const { observer, workflows = [], staticDir, onRun, config, agents = [], cache } = opts;
30
30
  const workflowByName = new Map(workflows.map((w) => [w.name, w]));
31
31
  // In-memory run registry — populated by listening to the observer.
32
32
  const runs = new Map();
@@ -97,15 +97,16 @@ export function createServer(opts) {
97
97
  const triggerType = w.nodes.find((n) => n.type.startsWith("trigger."))?.type ?? null;
98
98
  return {
99
99
  name: w.name,
100
+ title: w.title ?? w.name,
100
101
  nodeCount: w.nodes.length,
101
102
  triggerType,
102
103
  // Full graph so the editor can render each workflow without a second fetch.
103
104
  nodes: w.nodes,
104
105
  edges: w.edges,
105
- // Runnable from the browser only for ENTRY workflows. A `trigger.command` workflow is a
106
- // sub-workflow invoked by foreach/run-workflow with a payload running it standalone
107
- // gives it no trigger payload (empty keys → bad requests), so it isn't directly runnable.
108
- runnable: Boolean(onRun) && triggerType !== "trigger.command",
106
+ // Runnable from the browser when a run-trigger is wired. A `trigger.command` sub-workflow
107
+ // needs a payload (the editor prompts for one); entry workflows run with no payload.
108
+ runnable: Boolean(onRun),
109
+ needsPayload: triggerType === "trigger.command",
109
110
  };
110
111
  }));
111
112
  return;
@@ -119,25 +120,56 @@ export function createServer(opts) {
119
120
  let body = "";
120
121
  req.on("data", (c) => { body += c; });
121
122
  req.on("end", () => {
122
- let name;
123
+ let parsed;
123
124
  try {
124
- name = JSON.parse(body || "{}").workflow;
125
+ parsed = JSON.parse(body || "{}");
125
126
  }
126
127
  catch {
127
128
  json(res, { error: "invalid JSON body" }, 400);
128
129
  return;
129
130
  }
131
+ const name = parsed.workflow;
130
132
  if (!name || !workflowByName.has(name)) {
131
133
  json(res, { error: `unknown workflow: ${name ?? "(none)"}` }, 404);
132
134
  return;
133
135
  }
134
136
  // Don't await — the run streams over SSE; a thrown error is reported
135
137
  // there (and logged by the runner), so the server keeps serving.
136
- Promise.resolve(onRun(name)).catch(() => { });
138
+ Promise.resolve(onRun(name, parsed.payload)).catch(() => { });
137
139
  json(res, { started: name }, 202);
138
140
  });
139
141
  return;
140
142
  }
143
+ // Inspect / clear the engine seen-cache (debugging dedup state).
144
+ if (pathname === "/api/cache" && (req.method === "GET" || req.method === undefined)) {
145
+ json(res, cache ? cache.entries() : { seen: [], cursors: [] });
146
+ return;
147
+ }
148
+ if (pathname === "/api/cache" && req.method === "DELETE") {
149
+ if (!cache) {
150
+ json(res, { error: "cache not available" }, 405);
151
+ return;
152
+ }
153
+ let body = "";
154
+ req.on("data", (c) => { body += c; });
155
+ req.on("end", () => {
156
+ let key;
157
+ try {
158
+ key = JSON.parse(body || "{}").key;
159
+ }
160
+ catch {
161
+ json(res, { error: "invalid JSON body" }, 400);
162
+ return;
163
+ }
164
+ if (!key) {
165
+ json(res, { error: "missing key" }, 400);
166
+ return;
167
+ }
168
+ cache.forget(key);
169
+ json(res, { forgot: key }, 200);
170
+ });
171
+ return;
172
+ }
141
173
  if (pathname === "/api/config") {
142
174
  json(res, config ?? {});
143
175
  return;
package/dist/serve.d.ts CHANGED
@@ -9,8 +9,8 @@ export interface ServeOptions {
9
9
  observer?: StreamingObserver;
10
10
  /** Workflows to expose at /api/workflows (graph + run-eligibility). */
11
11
  workflows?: Workflow[];
12
- /** Trigger a run by name from the UI (POST /api/run). */
13
- onRun?: (name: string) => void | Promise<unknown>;
12
+ /** Trigger a run by name + optional payload from the UI (POST /api/run). */
13
+ onRun?: (name: string, payload?: unknown) => void | Promise<unknown>;
14
14
  /** Project config surfaced at GET /api/config (effective agent defaults, dryRun, version). */
15
15
  config?: {
16
16
  dryRun?: boolean;
@@ -22,6 +22,17 @@ export interface ServeOptions {
22
22
  };
23
23
  /** Agent definitions surfaced at GET /api/agents. */
24
24
  agents?: AgentDefinition[];
25
+ /** Engine cache, surfaced at GET/DELETE /api/cache for inspecting + clearing seen-state. */
26
+ cache?: {
27
+ entries(): {
28
+ seen: string[];
29
+ cursors: Array<{
30
+ key: string;
31
+ value: string;
32
+ }>;
33
+ };
34
+ forget(key: string): void;
35
+ };
25
36
  }
26
37
  /**
27
38
  * Locate the built editor assets to serve. Checks, in order:
package/dist/serve.js CHANGED
@@ -36,6 +36,7 @@ export function serve(opts = {}) {
36
36
  onRun: opts.onRun,
37
37
  config: opts.config,
38
38
  agents: opts.agents,
39
+ cache: opts.cache,
39
40
  });
40
41
  server.listen(port, host, () => {
41
42
  console.log(`[flow-server] listening on http://${host}:${port}`);
@@ -3,6 +3,8 @@ import type { RunObserver } from "@agentic-surfaces/core";
3
3
  export interface RunEvent {
4
4
  type: "run:start" | "node:start" | "node:finish" | "run:finish";
5
5
  workflow: string;
6
+ /** Short human label for the content this run is processing (from the trigger payload). */
7
+ label?: string;
6
8
  nodeId?: string;
7
9
  status?: "success" | "failed";
8
10
  meta?: unknown;
@@ -22,7 +24,7 @@ export declare class StreamingObserver implements RunObserver {
22
24
  getEvents(): readonly RunEvent[];
23
25
  /** Clear the event buffer (useful between test runs). */
24
26
  clear(): void;
25
- onRunStart(workflow: string): void;
27
+ onRunStart(workflow: string, payload?: unknown): void;
26
28
  onNodeStart(nodeId: string): void;
27
29
  onNodeFinish(nodeId: string, status: "success" | "failed", meta?: unknown): void;
28
30
  onRunFinish(workflow: string, status: "success" | "failed"): void;
@@ -1,3 +1,25 @@
1
+ /**
2
+ * A short label for what a run is processing, derived from its trigger payload — so a fan-out
3
+ * sub-run reads as e.g. "intake-idea · PD-109" instead of just the workflow name. Prefers a
4
+ * recognisable id field (Jira key/id), else a small JSON preview.
5
+ */
6
+ function runLabel(payload) {
7
+ if (payload == null || typeof payload !== "object") {
8
+ return payload == null ? undefined : String(payload).slice(0, 80);
9
+ }
10
+ const p = payload;
11
+ if (typeof p.key === "string")
12
+ return p.key; // Jira issue/JPD key (e.g. PD-109)
13
+ if (typeof p.id === "string" || typeof p.id === "number")
14
+ return String(p.id);
15
+ try {
16
+ const s = JSON.stringify(p);
17
+ return s.length > 80 ? s.slice(0, 80) + "…" : s;
18
+ }
19
+ catch {
20
+ return undefined;
21
+ }
22
+ }
1
23
  /** Max characters of a node's output we put on the wire — enough to debug, bounded
2
24
  * so a large HTTP response (e.g. a full comment thread) can't bloat the SSE stream. */
3
25
  const OUTPUT_PREVIEW_CAP = 16_000;
@@ -50,8 +72,8 @@ export class StreamingObserver {
50
72
  this.events = [];
51
73
  }
52
74
  // ── RunObserver interface ──────────────────────────────────────────────────
53
- onRunStart(workflow) {
54
- this.emit({ type: "run:start", workflow, ts: Date.now() });
75
+ onRunStart(workflow, payload) {
76
+ this.emit({ type: "run:start", workflow, label: runLabel(payload), ts: Date.now() });
55
77
  }
56
78
  onNodeStart(nodeId) {
57
79
  // workflow name is unknown at this call-site in the core interface;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentic-surfaces/server",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -21,7 +21,7 @@
21
21
  "dist"
22
22
  ],
23
23
  "dependencies": {
24
- "@agentic-surfaces/core": "0.1.17"
24
+ "@agentic-surfaces/core": "0.1.19"
25
25
  },
26
26
  "scripts": {
27
27
  "build": "tsc -b",