@redtuma/deployer 0.1.0 → 0.2.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.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -9
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;UAUiB,uBAAA;;;AAAjB;AA+CA;;;;;AAkHA;;;;;;;AAA+E,iBAlH/D,gBAAA,CAkH+D,OAAA,EAlHrC,OAkHqC,EAAA,IAAA,CAAA,EAlHtB,uBAkHsB,CAAA,EAlHS,IAkHT;;;;iBAA/D,cAAA,UAAwB,gBAAgB,oCAAuB,uCAAA,KAAA,CAAA,qBAAA,WAAA,QAAA"}
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,7 @@ function findWorkflow(redtuma, id) {
|
|
|
29
29
|
function createHonoServer(redtuma, opts = {}) {
|
|
30
30
|
const app = opts.basePath ? new Hono().basePath(opts.basePath) : new Hono();
|
|
31
31
|
const runs = /* @__PURE__ */ new Map();
|
|
32
|
+
const snapshotKey = (workflowId, runId) => `wf:${workflowId}:run:${runId}`;
|
|
32
33
|
app.onError((err, c) => {
|
|
33
34
|
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
34
35
|
});
|
|
@@ -75,28 +76,39 @@ function createHonoServer(redtuma, opts = {}) {
|
|
|
75
76
|
const run = workflow.createRun();
|
|
76
77
|
const result = await run.start({ inputData: body.inputData });
|
|
77
78
|
const runId = globalThis.crypto.randomUUID();
|
|
78
|
-
if (result.status === "suspended")
|
|
79
|
+
if (result.status === "suspended") {
|
|
80
|
+
const storage = redtuma.getStorage();
|
|
81
|
+
if (storage) await storage.persistSnapshot(snapshotKey(workflow.id, runId), run.getSnapshot());
|
|
82
|
+
else runs.set(runId, run);
|
|
83
|
+
}
|
|
79
84
|
return c.json({
|
|
80
85
|
...result,
|
|
81
86
|
runId
|
|
82
87
|
});
|
|
83
88
|
});
|
|
84
89
|
app.post("/api/workflows/:id/resume", async (c) => {
|
|
85
|
-
|
|
90
|
+
const workflow = findWorkflow(redtuma, c.req.param("id"));
|
|
91
|
+
if (!workflow) return c.json({ error: `Workflow "${c.req.param("id")}" not found.` }, 404);
|
|
86
92
|
const body = await c.req.json().catch(() => ({}));
|
|
87
93
|
if (!body.runId) return c.json({ error: "Request must include `runId`." }, 400);
|
|
88
94
|
if (!body.step) return c.json({ error: "Request must include `step`." }, 400);
|
|
89
|
-
const
|
|
90
|
-
|
|
95
|
+
const storage = redtuma.getStorage();
|
|
96
|
+
const key = snapshotKey(workflow.id, body.runId);
|
|
97
|
+
let run;
|
|
98
|
+
if (storage) {
|
|
99
|
+
const snapshot = await storage.loadSnapshot(key);
|
|
100
|
+
if (!snapshot) return c.json({ error: `Run "${body.runId}" not found.` }, 404);
|
|
101
|
+
run = workflow.createRun().restore(snapshot);
|
|
102
|
+
} else {
|
|
103
|
+
run = runs.get(body.runId);
|
|
104
|
+
if (!run) return c.json({ error: `Run "${body.runId}" not found.` }, 404);
|
|
105
|
+
}
|
|
91
106
|
const result = await run.resume({
|
|
92
107
|
step: body.step,
|
|
93
108
|
resumeData: body.resumeData
|
|
94
109
|
});
|
|
95
|
-
if (result.status === "suspended"
|
|
96
|
-
|
|
97
|
-
runId: body.runId
|
|
98
|
-
});
|
|
99
|
-
runs.delete(body.runId);
|
|
110
|
+
if (storage) await storage.persistSnapshot(key, result.status === "suspended" ? run.getSnapshot() : null);
|
|
111
|
+
else if (result.status !== "suspended") runs.delete(body.runId);
|
|
100
112
|
return c.json({
|
|
101
113
|
...result,
|
|
102
114
|
runId: body.runId
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { Hono } from 'hono'\nimport { stream } from 'hono/streaming'\nimport type {\n Redtuma,\n CoreMessage,\n GenerateOptions,\n Run,\n} from '@redtuma/core'\n\nexport interface CreateHonoServerOptions {\n /** Mount all routes under this prefix (e.g. `/api/v1`). */\n basePath?: string\n}\n\ninterface GenerateBody {\n messages?: CoreMessage[]\n input?: string\n options?: GenerateOptions\n}\n\ninterface RunBody {\n inputData?: unknown\n}\n\ninterface ResumeBody {\n runId?: string\n step?: string\n resumeData?: unknown\n}\n\n/** Resolve an agent by its `id`, returning undefined instead of throwing. */\nfunction findAgent(redtuma: Redtuma, id: string) {\n try {\n return redtuma.getAgentById(id)\n } catch {\n return undefined\n }\n}\n\n/** Resolve a workflow by its `id` (not necessarily its registry key). */\nfunction findWorkflow(redtuma: Redtuma, id: string) {\n return Object.values(redtuma.getWorkflows()).find((wf) => wf.id === id)\n}\n\n/**\n * Build a Hono app exposing a Redtuma's agents and workflows over HTTP.\n *\n * Routes (all JSON unless noted):\n * - `GET /` health check\n * - `GET /api/agents` list registered agents\n * - `POST /api/agents/:id/generate` run `agent.generate`\n * - `POST /api/agents/:id/stream` stream `agent.stream` as text/plain\n * - `GET /api/workflows` list registered workflows\n * - `POST /api/workflows/:id/run` start a workflow run\n * - `POST /api/workflows/:id/resume` resume a suspended run\n */\nexport function createHonoServer(redtuma: Redtuma, opts: CreateHonoServerOptions = {}): Hono {\n const app = opts.basePath ? new Hono().basePath(opts.basePath) : new Hono()\n\n // Suspended
|
|
1
|
+
{"version":3,"file":"index.js","names":["run: Run | undefined"],"sources":["../src/index.ts"],"sourcesContent":["import { Hono } from 'hono'\nimport { stream } from 'hono/streaming'\nimport type {\n Redtuma,\n CoreMessage,\n GenerateOptions,\n Run,\n RunSnapshot,\n} from '@redtuma/core'\n\nexport interface CreateHonoServerOptions {\n /** Mount all routes under this prefix (e.g. `/api/v1`). */\n basePath?: string\n}\n\ninterface GenerateBody {\n messages?: CoreMessage[]\n input?: string\n options?: GenerateOptions\n}\n\ninterface RunBody {\n inputData?: unknown\n}\n\ninterface ResumeBody {\n runId?: string\n step?: string\n resumeData?: unknown\n}\n\n/** Resolve an agent by its `id`, returning undefined instead of throwing. */\nfunction findAgent(redtuma: Redtuma, id: string) {\n try {\n return redtuma.getAgentById(id)\n } catch {\n return undefined\n }\n}\n\n/** Resolve a workflow by its `id` (not necessarily its registry key). */\nfunction findWorkflow(redtuma: Redtuma, id: string) {\n return Object.values(redtuma.getWorkflows()).find((wf) => wf.id === id)\n}\n\n/**\n * Build a Hono app exposing a Redtuma's agents and workflows over HTTP.\n *\n * Routes (all JSON unless noted):\n * - `GET /` health check\n * - `GET /api/agents` list registered agents\n * - `POST /api/agents/:id/generate` run `agent.generate`\n * - `POST /api/agents/:id/stream` stream `agent.stream` as text/plain\n * - `GET /api/workflows` list registered workflows\n * - `POST /api/workflows/:id/run` start a workflow run\n * - `POST /api/workflows/:id/resume` resume a suspended run\n */\nexport function createHonoServer(redtuma: Redtuma, opts: CreateHonoServerOptions = {}): Hono {\n const app = opts.basePath ? new Hono().basePath(opts.basePath) : new Hono()\n\n // Suspended runs are persisted to the configured Store when one is present, so\n // `/resume` works across instances and restarts (required for stateless edge\n // deploys). Without storage we fall back to an in-process Map (single-instance).\n const runs = new Map<string, Run>()\n const snapshotKey = (workflowId: string, runId: string) => `wf:${workflowId}:run:${runId}`\n\n app.onError((err, c) => {\n return c.json({ error: err instanceof Error ? err.message : String(err) }, 500)\n })\n\n app.get('/', (c) => c.json({ name: 'redtuma', status: 'ok' }))\n\n app.get('/api/agents', (c) => {\n const agents = Object.values(redtuma.getAgents()).map((a) => ({ id: a.id, name: a.name }))\n return c.json(agents)\n })\n\n app.post('/api/agents/:id/generate', async (c) => {\n const agent = findAgent(redtuma, c.req.param('id'))\n if (!agent) return c.json({ error: `Agent \"${c.req.param('id')}\" not found.` }, 404)\n\n const body = await c.req.json<GenerateBody>().catch(() => ({}) as GenerateBody)\n const input = body.input ?? body.messages\n if (input === undefined) {\n return c.json({ error: 'Request must include `input` (string) or `messages`.' }, 400)\n }\n\n const result = await agent.generate(input, body.options)\n return c.json(result)\n })\n\n app.post('/api/agents/:id/stream', async (c) => {\n const agent = findAgent(redtuma, c.req.param('id'))\n if (!agent) return c.json({ error: `Agent \"${c.req.param('id')}\" not found.` }, 404)\n\n const body = await c.req.json<GenerateBody>().catch(() => ({}) as GenerateBody)\n const input = body.input ?? body.messages\n if (input === undefined) {\n return c.json({ error: 'Request must include `input` (string) or `messages`.' }, 400)\n }\n\n c.header('Content-Type', 'text/plain; charset=utf-8')\n return stream(c, async (s) => {\n const result = await agent.stream(input, body.options)\n for await (const chunk of result.textStream) {\n await s.write(chunk)\n }\n })\n })\n\n app.get('/api/workflows', (c) => {\n const workflows = Object.values(redtuma.getWorkflows()).map((wf) => ({ id: wf.id }))\n return c.json(workflows)\n })\n\n app.post('/api/workflows/:id/run', async (c) => {\n const workflow = findWorkflow(redtuma, c.req.param('id'))\n if (!workflow) return c.json({ error: `Workflow \"${c.req.param('id')}\" not found.` }, 404)\n\n const body = await c.req.json<RunBody>().catch(() => ({}) as RunBody)\n const run = workflow.createRun()\n const result = await run.start({ inputData: body.inputData })\n\n // Hand back a runId so a suspended run can be resumed later.\n const runId = globalThis.crypto.randomUUID()\n if (result.status === 'suspended') {\n const storage = redtuma.getStorage()\n if (storage) await storage.persistSnapshot(snapshotKey(workflow.id, runId), run.getSnapshot())\n else runs.set(runId, run)\n }\n return c.json({ ...result, runId })\n })\n\n app.post('/api/workflows/:id/resume', async (c) => {\n const workflow = findWorkflow(redtuma, c.req.param('id'))\n if (!workflow) return c.json({ error: `Workflow \"${c.req.param('id')}\" not found.` }, 404)\n\n const body = await c.req.json<ResumeBody>().catch(() => ({}) as ResumeBody)\n if (!body.runId) return c.json({ error: 'Request must include `runId`.' }, 400)\n if (!body.step) return c.json({ error: 'Request must include `step`.' }, 400)\n\n const storage = redtuma.getStorage()\n const key = snapshotKey(workflow.id, body.runId)\n\n let run: Run | undefined\n if (storage) {\n const snapshot = await storage.loadSnapshot<RunSnapshot>(key)\n if (!snapshot) return c.json({ error: `Run \"${body.runId}\" not found.` }, 404)\n run = workflow.createRun().restore(snapshot)\n } else {\n run = runs.get(body.runId)\n if (!run) return c.json({ error: `Run \"${body.runId}\" not found.` }, 404)\n }\n\n const result = await run.resume({ step: body.step, resumeData: body.resumeData })\n\n if (storage) {\n // Persist the new snapshot if still suspended; otherwise clear it.\n await storage.persistSnapshot(key, result.status === 'suspended' ? run.getSnapshot() : null)\n } else if (result.status !== 'suspended') {\n runs.delete(body.runId)\n }\n return c.json({ ...result, runId: body.runId })\n })\n\n return app\n}\n\n/**\n * Convenience for edge/Workers runtimes: returns the app's `fetch` handler.\n */\nexport function toFetchHandler(redtuma: Redtuma, opts?: CreateHonoServerOptions) {\n return createHonoServer(redtuma, opts).fetch\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redtuma/deployer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Redtuma deployer: Hono server adapter exposing agents and workflows over HTTP.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"hono": "^4.6.0",
|
|
19
|
-
"@redtuma/core": "0.
|
|
19
|
+
"@redtuma/core": "0.2.0"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/redtuma
|
|
23
|
+
"url": "git+https://github.com/redtuma/redtuma.git",
|
|
24
24
|
"directory": "packages/deployer"
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://redtuma.ai",
|
|
27
|
-
"bugs": "https://github.com/redtuma
|
|
27
|
+
"bugs": "https://github.com/redtuma/redtuma/issues",
|
|
28
28
|
"keywords": [
|
|
29
29
|
"ai",
|
|
30
30
|
"agents",
|