@almadar/sdk 0.1.0-alpha.2
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/LICENSE +72 -0
- package/README.md +63 -0
- package/dist/client/index.d.ts +58 -0
- package/dist/client/index.js +282 -0
- package/dist/client/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +328 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.d.ts +9 -0
- package/dist/react/index.js +49 -0
- package/dist/react/index.js.map +1 -0
- package/dist/server/index.d.ts +61 -0
- package/dist/server/index.js +280 -0
- package/dist/server/index.js.map +1 -0
- package/dist/types-BfWDIOGm.d.ts +145 -0
- package/package.json +100 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { PauseController, isTraceEvent, traceToSSE, runRabit, runContextualEdit } from '@almadar-io/rabit';
|
|
2
|
+
import { setupSSE, sendSSEEvent, closeSSE } from '@almadar/server';
|
|
3
|
+
|
|
4
|
+
// src/server/index.ts
|
|
5
|
+
function resolveUserId(opts, req) {
|
|
6
|
+
if (opts.userId) return opts.userId(req);
|
|
7
|
+
const header = req.headers["x-user-id"];
|
|
8
|
+
return typeof header === "string" && header.length > 0 ? header : "anonymous";
|
|
9
|
+
}
|
|
10
|
+
async function resolveExtraProviderConfig(opts, provider) {
|
|
11
|
+
if (!opts.resolveProviderConfig) return void 0;
|
|
12
|
+
return opts.resolveProviderConfig(provider);
|
|
13
|
+
}
|
|
14
|
+
function makeThreadId(workspace) {
|
|
15
|
+
return workspace.appId ?? `sdk-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
16
|
+
}
|
|
17
|
+
function createGenerateHandler(opts) {
|
|
18
|
+
return async (req, res) => {
|
|
19
|
+
const body = req.body;
|
|
20
|
+
const rawPrompt = body["prompt"] ?? body["message"];
|
|
21
|
+
const prompt = typeof rawPrompt === "string" ? rawPrompt : "";
|
|
22
|
+
if (!prompt) {
|
|
23
|
+
res.status(400).json({ error: "prompt or message is required" });
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const provider = (typeof body["provider"] === "string" ? body["provider"] : void 0) ?? opts.provider ?? "deepseek";
|
|
27
|
+
const model = (typeof body["model"] === "string" ? body["model"] : void 0) ?? opts.model ?? "deepseek-v4-flash";
|
|
28
|
+
const userId = resolveUserId(opts, req);
|
|
29
|
+
let workspace;
|
|
30
|
+
try {
|
|
31
|
+
workspace = await opts.workspaceFactory(req);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
34
|
+
res.status(500).json({ error: `Workspace open failed: ${message}` });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
setupSSE(res);
|
|
38
|
+
const threadId = makeThreadId(workspace);
|
|
39
|
+
const abortController = new AbortController();
|
|
40
|
+
const pauseController = new PauseController();
|
|
41
|
+
const ctx = {
|
|
42
|
+
threadId,
|
|
43
|
+
workDir: workspace.workDir,
|
|
44
|
+
userId,
|
|
45
|
+
...workspace.appId !== void 0 ? { appId: workspace.appId } : {}
|
|
46
|
+
};
|
|
47
|
+
const unsubscribe = workspace.subscribe({
|
|
48
|
+
onWrite(event) {
|
|
49
|
+
if (event.kind !== "trace") return;
|
|
50
|
+
if (!isTraceEvent(event.event)) return;
|
|
51
|
+
for (const sseEvent of traceToSSE(event.event, ctx)) {
|
|
52
|
+
sendSSEEvent(res, sseEvent);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
sendSSEEvent(res, {
|
|
57
|
+
type: "start",
|
|
58
|
+
data: { threadId, skill: "rabit", workDir: workspace.workDir },
|
|
59
|
+
timestamp: Date.now()
|
|
60
|
+
});
|
|
61
|
+
res.on("close", () => {
|
|
62
|
+
abortController.abort();
|
|
63
|
+
});
|
|
64
|
+
const catalogMode = opts.catalogScope?.mode;
|
|
65
|
+
const stdAllowList = opts.catalogScope?.stdAllowList;
|
|
66
|
+
const extraProviderConfig = await resolveExtraProviderConfig(opts, provider);
|
|
67
|
+
const rabitOpts = {
|
|
68
|
+
prompt,
|
|
69
|
+
workDir: workspace.workDir,
|
|
70
|
+
userId,
|
|
71
|
+
provider,
|
|
72
|
+
model,
|
|
73
|
+
workspace,
|
|
74
|
+
signal: abortController.signal,
|
|
75
|
+
pauseController,
|
|
76
|
+
...catalogMode !== void 0 ? { catalogMode } : {},
|
|
77
|
+
...stdAllowList !== void 0 ? { stdAllowList } : {},
|
|
78
|
+
...extraProviderConfig !== void 0 ? { providerConfig: extraProviderConfig } : {}
|
|
79
|
+
};
|
|
80
|
+
try {
|
|
81
|
+
const result = await runRabit(rabitOpts);
|
|
82
|
+
if (result.success && result.composedSchema !== null) {
|
|
83
|
+
sendSSEEvent(res, {
|
|
84
|
+
type: "complete",
|
|
85
|
+
data: {
|
|
86
|
+
threadId,
|
|
87
|
+
skill: "rabit",
|
|
88
|
+
workDir: workspace.workDir,
|
|
89
|
+
schemaGenerated: true,
|
|
90
|
+
appCompiled: false,
|
|
91
|
+
schema: result.composedSchema,
|
|
92
|
+
...workspace.appId !== void 0 ? { appId: workspace.appId } : {}
|
|
93
|
+
},
|
|
94
|
+
timestamp: Date.now()
|
|
95
|
+
});
|
|
96
|
+
try {
|
|
97
|
+
await opts.onComplete?.(result.composedSchema, req);
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
} else if (result.success) {
|
|
101
|
+
sendSSEEvent(res, {
|
|
102
|
+
type: "complete",
|
|
103
|
+
data: {
|
|
104
|
+
threadId,
|
|
105
|
+
skill: "rabit",
|
|
106
|
+
workDir: workspace.workDir,
|
|
107
|
+
schemaGenerated: false,
|
|
108
|
+
appCompiled: false
|
|
109
|
+
},
|
|
110
|
+
timestamp: Date.now()
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
const failList = result.failedOrbitals.join(", ");
|
|
114
|
+
sendSSEEvent(res, {
|
|
115
|
+
type: "error",
|
|
116
|
+
data: {
|
|
117
|
+
error: `Generation failed${failList.length > 0 ? `: ${failList}` : ""}`,
|
|
118
|
+
code: "failed"
|
|
119
|
+
},
|
|
120
|
+
timestamp: Date.now()
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
const isAbort = err instanceof Error && (err.name === "AbortError" || abortController.signal.aborted);
|
|
125
|
+
if (isAbort) {
|
|
126
|
+
sendSSEEvent(res, {
|
|
127
|
+
type: "cancelled",
|
|
128
|
+
data: { threadId, message: "Generation cancelled" },
|
|
129
|
+
timestamp: Date.now()
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
133
|
+
sendSSEEvent(res, {
|
|
134
|
+
type: "error",
|
|
135
|
+
data: { error: message, code: "runtime" },
|
|
136
|
+
timestamp: Date.now()
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
} finally {
|
|
140
|
+
try {
|
|
141
|
+
unsubscribe();
|
|
142
|
+
} catch {
|
|
143
|
+
}
|
|
144
|
+
closeSSE(res);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function createEditHandler(opts) {
|
|
149
|
+
const generateHandler = createGenerateHandler(opts);
|
|
150
|
+
return async (req, res) => {
|
|
151
|
+
const body = req.body;
|
|
152
|
+
const focus = body["focus"];
|
|
153
|
+
if (focus === void 0 || focus === null) {
|
|
154
|
+
return generateHandler(req, res);
|
|
155
|
+
}
|
|
156
|
+
const rawInstruction = body["instruction"] ?? body["message"];
|
|
157
|
+
const instruction = typeof rawInstruction === "string" ? rawInstruction : "";
|
|
158
|
+
if (!instruction) {
|
|
159
|
+
res.status(400).json({ error: "instruction or message is required" });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const provider = (typeof body["provider"] === "string" ? body["provider"] : void 0) ?? opts.provider ?? "deepseek";
|
|
163
|
+
const model = (typeof body["model"] === "string" ? body["model"] : void 0) ?? opts.model ?? "deepseek-v4-flash";
|
|
164
|
+
const userId = resolveUserId(opts, req);
|
|
165
|
+
let workspace;
|
|
166
|
+
try {
|
|
167
|
+
workspace = await opts.workspaceFactory(req);
|
|
168
|
+
} catch (err) {
|
|
169
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
170
|
+
res.status(500).json({ error: `Workspace open failed: ${message}` });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
setupSSE(res);
|
|
174
|
+
const threadId = makeThreadId(workspace);
|
|
175
|
+
const abortController = new AbortController();
|
|
176
|
+
const ctx = {
|
|
177
|
+
threadId,
|
|
178
|
+
workDir: workspace.workDir,
|
|
179
|
+
userId,
|
|
180
|
+
...workspace.appId !== void 0 ? { appId: workspace.appId } : {}
|
|
181
|
+
};
|
|
182
|
+
const unsubscribe = workspace.subscribe({
|
|
183
|
+
onWrite(event) {
|
|
184
|
+
if (event.kind !== "trace") return;
|
|
185
|
+
if (!isTraceEvent(event.event)) return;
|
|
186
|
+
for (const sseEvent of traceToSSE(event.event, ctx)) {
|
|
187
|
+
sendSSEEvent(res, sseEvent);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
sendSSEEvent(res, {
|
|
192
|
+
type: "start",
|
|
193
|
+
data: { threadId, skill: "rabit", workDir: workspace.workDir },
|
|
194
|
+
timestamp: Date.now()
|
|
195
|
+
});
|
|
196
|
+
res.on("close", () => {
|
|
197
|
+
abortController.abort();
|
|
198
|
+
});
|
|
199
|
+
const extraProviderConfig = await resolveExtraProviderConfig(opts, provider);
|
|
200
|
+
try {
|
|
201
|
+
const editResult = await runContextualEdit({
|
|
202
|
+
// EditFocus is validated at runtime by rabit; we pass through as-is.
|
|
203
|
+
focus,
|
|
204
|
+
instruction,
|
|
205
|
+
workDir: workspace.workDir,
|
|
206
|
+
provider,
|
|
207
|
+
model,
|
|
208
|
+
userId,
|
|
209
|
+
workspace,
|
|
210
|
+
signal: abortController.signal,
|
|
211
|
+
...extraProviderConfig !== void 0 ? { providerConfig: extraProviderConfig } : {}
|
|
212
|
+
});
|
|
213
|
+
if (!editResult.success) {
|
|
214
|
+
sendSSEEvent(res, {
|
|
215
|
+
type: "error",
|
|
216
|
+
data: {
|
|
217
|
+
error: editResult.error ?? "The edit did not change anything.",
|
|
218
|
+
code: "failed"
|
|
219
|
+
},
|
|
220
|
+
timestamp: Date.now()
|
|
221
|
+
});
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const rawSchema = workspace.readSchema();
|
|
225
|
+
let composedSchema = null;
|
|
226
|
+
if (rawSchema !== null) {
|
|
227
|
+
try {
|
|
228
|
+
composedSchema = JSON.parse(rawSchema);
|
|
229
|
+
} catch {
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
sendSSEEvent(res, {
|
|
233
|
+
type: "complete",
|
|
234
|
+
data: {
|
|
235
|
+
threadId,
|
|
236
|
+
skill: "rabit",
|
|
237
|
+
workDir: workspace.workDir,
|
|
238
|
+
schemaGenerated: composedSchema !== null,
|
|
239
|
+
appCompiled: false,
|
|
240
|
+
schemaPersisted: false,
|
|
241
|
+
...composedSchema !== null ? { schema: composedSchema } : {},
|
|
242
|
+
...workspace.appId !== void 0 ? { appId: workspace.appId } : {}
|
|
243
|
+
},
|
|
244
|
+
timestamp: Date.now()
|
|
245
|
+
});
|
|
246
|
+
if (composedSchema !== null) {
|
|
247
|
+
try {
|
|
248
|
+
await opts.onComplete?.(composedSchema, req);
|
|
249
|
+
} catch {
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
} catch (err) {
|
|
253
|
+
const isAbort = err instanceof Error && (err.name === "AbortError" || abortController.signal.aborted);
|
|
254
|
+
if (isAbort) {
|
|
255
|
+
sendSSEEvent(res, {
|
|
256
|
+
type: "cancelled",
|
|
257
|
+
data: { threadId, message: "Edit cancelled" },
|
|
258
|
+
timestamp: Date.now()
|
|
259
|
+
});
|
|
260
|
+
} else {
|
|
261
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
262
|
+
sendSSEEvent(res, {
|
|
263
|
+
type: "error",
|
|
264
|
+
data: { error: message, code: "runtime" },
|
|
265
|
+
timestamp: Date.now()
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
} finally {
|
|
269
|
+
try {
|
|
270
|
+
unsubscribe();
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
273
|
+
closeSSE(res);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export { createEditHandler, createGenerateHandler };
|
|
279
|
+
//# sourceMappingURL=index.js.map
|
|
280
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/server/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * `@almadar/sdk/server` — Express handler factories for the Almadar agent.\n *\n * Node-only. Never import this from browser or React code.\n *\n * Usage:\n * import { createGenerateHandler, createEditHandler } from '@almadar/sdk/server';\n */\n\nimport type { Request, Response } from 'express';\nimport type { WorkspaceService } from '@almadar/workspace';\nimport type { OrbitalSchema } from '@almadar/core';\nimport type { ProviderConfig } from '@almadar/llm';\nimport {\n runRabit,\n runContextualEdit,\n PauseController,\n traceToSSE,\n isTraceEvent,\n type RabitOptions,\n type MapperContext,\n} from '@almadar-io/rabit';\nimport {\n setupSSE,\n sendSSEEvent,\n closeSSE,\n} from '@almadar/server';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n// Canonical provider-credential type lives in `@almadar/llm`; re-export it so\n// callers get the exact shape `runRabit` consumes without a local shadow.\nexport type { ProviderConfig };\n\n// ============================================================================\n// Public option surface\n// ============================================================================\n\nexport interface GenerateHandlerOptions {\n /** Open (or return) the workspace for this request. */\n workspaceFactory: (req: Request) => Promise<WorkspaceService> | WorkspaceService;\n /** LLM provider — defaults to `'deepseek'`. */\n provider?: string;\n /** LLM model — defaults to `'deepseek-v4-flash'`. */\n model?: string;\n /** Std-catalog scope forwarded to rabit. */\n catalogScope?: {\n mode: 'extend' | 'subset' | 'replace';\n stdAllowList?: readonly string[];\n };\n /** Return explicit provider credentials for the given provider string. */\n resolveProviderConfig?: (\n provider: string,\n ) => Promise<ProviderConfig | undefined> | ProviderConfig | undefined;\n /** Called once with the final composed schema after a successful generate. */\n onComplete?: (schema: OrbitalSchema, req: Request) => Promise<void> | void;\n /** Derive a stable user id from the request — defaults to `'anonymous'`. */\n userId?: (req: Request) => string;\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nfunction resolveUserId(opts: GenerateHandlerOptions, req: Request): string {\n if (opts.userId) return opts.userId(req);\n const header = req.headers['x-user-id'];\n return typeof header === 'string' && header.length > 0 ? header : 'anonymous';\n}\n\nasync function resolveExtraProviderConfig(\n opts: GenerateHandlerOptions,\n provider: string,\n): Promise<ProviderConfig | undefined> {\n if (!opts.resolveProviderConfig) return undefined;\n return opts.resolveProviderConfig(provider);\n}\n\nfunction makeThreadId(workspace: WorkspaceService): string {\n return (\n workspace.appId ??\n `sdk-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n );\n}\n\n// ============================================================================\n// createGenerateHandler\n// ============================================================================\n\n/**\n * Returns an Express route handler that streams a rabit generation run as SSE.\n *\n * Body shape accepted:\n * `{ prompt?: string; message?: string; provider?: string; model?: string; appId?: string }`\n *\n * SSE events emitted:\n * `start` → trace fan-out → `complete | error | cancelled`\n */\nexport function createGenerateHandler(\n opts: GenerateHandlerOptions,\n): (req: Request, res: Response) => Promise<void> {\n return async (req: Request, res: Response): Promise<void> => {\n const body = req.body as Record<string, unknown>;\n const rawPrompt = body['prompt'] ?? body['message'];\n const prompt = typeof rawPrompt === 'string' ? rawPrompt : '';\n\n if (!prompt) {\n res.status(400).json({ error: 'prompt or message is required' });\n return;\n }\n\n const provider =\n (typeof body['provider'] === 'string' ? body['provider'] : undefined) ??\n opts.provider ??\n 'deepseek';\n const model =\n (typeof body['model'] === 'string' ? body['model'] : undefined) ??\n opts.model ??\n 'deepseek-v4-flash';\n const userId = resolveUserId(opts, req);\n\n let workspace: WorkspaceService;\n try {\n workspace = await opts.workspaceFactory(req);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n res.status(500).json({ error: `Workspace open failed: ${message}` });\n return;\n }\n\n setupSSE(res);\n\n const threadId = makeThreadId(workspace);\n const abortController = new AbortController();\n const pauseController = new PauseController();\n\n const ctx: MapperContext = {\n threadId,\n workDir: workspace.workDir,\n userId,\n ...(workspace.appId !== undefined ? { appId: workspace.appId } : {}),\n };\n\n const unsubscribe = workspace.subscribe({\n onWrite(event) {\n if (event.kind !== 'trace') return;\n if (!isTraceEvent(event.event)) return;\n for (const sseEvent of traceToSSE(event.event, ctx)) {\n sendSSEEvent(res, sseEvent);\n }\n },\n });\n\n sendSSEEvent(res, {\n type: 'start',\n data: { threadId, skill: 'rabit', workDir: workspace.workDir },\n timestamp: Date.now(),\n });\n\n res.on('close', () => {\n abortController.abort();\n });\n\n const catalogMode = opts.catalogScope?.mode;\n const stdAllowList = opts.catalogScope?.stdAllowList;\n const extraProviderConfig = await resolveExtraProviderConfig(opts, provider);\n\n const rabitOpts: RabitOptions = {\n prompt,\n workDir: workspace.workDir,\n userId,\n provider,\n model,\n workspace,\n signal: abortController.signal,\n pauseController,\n ...(catalogMode !== undefined ? { catalogMode } : {}),\n ...(stdAllowList !== undefined ? { stdAllowList } : {}),\n ...(extraProviderConfig !== undefined ? { providerConfig: extraProviderConfig } : {}),\n };\n\n try {\n const result = await runRabit(rabitOpts);\n\n if (result.success && result.composedSchema !== null) {\n sendSSEEvent(res, {\n type: 'complete',\n data: {\n threadId,\n skill: 'rabit',\n workDir: workspace.workDir,\n schemaGenerated: true,\n appCompiled: false,\n schema: result.composedSchema,\n ...(workspace.appId !== undefined ? { appId: workspace.appId } : {}),\n },\n timestamp: Date.now(),\n });\n try {\n await opts.onComplete?.(result.composedSchema, req);\n } catch {\n // onComplete errors do not fail the SSE stream — schema was generated\n }\n } else if (result.success) {\n sendSSEEvent(res, {\n type: 'complete',\n data: {\n threadId,\n skill: 'rabit',\n workDir: workspace.workDir,\n schemaGenerated: false,\n appCompiled: false,\n },\n timestamp: Date.now(),\n });\n } else {\n const failList = result.failedOrbitals.join(', ');\n sendSSEEvent(res, {\n type: 'error',\n data: {\n error: `Generation failed${failList.length > 0 ? `: ${failList}` : ''}`,\n code: 'failed',\n },\n timestamp: Date.now(),\n });\n }\n } catch (err: unknown) {\n const isAbort =\n err instanceof Error &&\n (err.name === 'AbortError' || abortController.signal.aborted);\n if (isAbort) {\n sendSSEEvent(res, {\n type: 'cancelled',\n data: { threadId, message: 'Generation cancelled' },\n timestamp: Date.now(),\n });\n } else {\n const message = err instanceof Error ? err.message : String(err);\n sendSSEEvent(res, {\n type: 'error',\n data: { error: message, code: 'runtime' },\n timestamp: Date.now(),\n });\n }\n } finally {\n try {\n unsubscribe();\n } catch {\n // best-effort\n }\n closeSSE(res);\n }\n };\n}\n\n// ============================================================================\n// createEditHandler\n// ============================================================================\n\n/**\n * Returns an Express route handler that streams a contextual-edit run as SSE.\n *\n * Body shape accepted:\n * `{ focus: EditFocus; instruction?: string; message?: string; provider?: string; model?: string }`\n *\n * The `focus` field must be a valid `EditFocus` (orbital + trait + patternType\n * + path — see `@almadar/core`'s `EditFocus` type). The handler delegates\n * entirely to `runContextualEdit` from `@almadar-io/rabit`.\n *\n * TODO: when `focus` is absent the handler falls back to a full-regeneration\n * pass (`createGenerateHandler` semantics). Wire a dedicated delta-prompt edit\n * path here once rabit exposes a `runDeltaEdit` entry point.\n */\nexport function createEditHandler(\n opts: GenerateHandlerOptions,\n): (req: Request, res: Response) => Promise<void> {\n const generateHandler = createGenerateHandler(opts);\n\n return async (req: Request, res: Response): Promise<void> => {\n const body = req.body as Record<string, unknown>;\n const focus = body['focus'];\n\n // Without a focus, fall back to a full regeneration pass.\n if (focus === undefined || focus === null) {\n return generateHandler(req, res);\n }\n\n const rawInstruction = body['instruction'] ?? body['message'];\n const instruction =\n typeof rawInstruction === 'string' ? rawInstruction : '';\n\n if (!instruction) {\n res.status(400).json({ error: 'instruction or message is required' });\n return;\n }\n\n const provider =\n (typeof body['provider'] === 'string' ? body['provider'] : undefined) ??\n opts.provider ??\n 'deepseek';\n const model =\n (typeof body['model'] === 'string' ? body['model'] : undefined) ??\n opts.model ??\n 'deepseek-v4-flash';\n const userId = resolveUserId(opts, req);\n\n let workspace: WorkspaceService;\n try {\n workspace = await opts.workspaceFactory(req);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n res.status(500).json({ error: `Workspace open failed: ${message}` });\n return;\n }\n\n setupSSE(res);\n\n const threadId = makeThreadId(workspace);\n const abortController = new AbortController();\n\n const ctx: MapperContext = {\n threadId,\n workDir: workspace.workDir,\n userId,\n ...(workspace.appId !== undefined ? { appId: workspace.appId } : {}),\n };\n\n const unsubscribe = workspace.subscribe({\n onWrite(event) {\n if (event.kind !== 'trace') return;\n if (!isTraceEvent(event.event)) return;\n for (const sseEvent of traceToSSE(event.event, ctx)) {\n sendSSEEvent(res, sseEvent);\n }\n },\n });\n\n sendSSEEvent(res, {\n type: 'start',\n data: { threadId, skill: 'rabit', workDir: workspace.workDir },\n timestamp: Date.now(),\n });\n\n res.on('close', () => {\n abortController.abort();\n });\n\n const extraProviderConfig = await resolveExtraProviderConfig(opts, provider);\n\n try {\n const editResult = await runContextualEdit({\n // EditFocus is validated at runtime by rabit; we pass through as-is.\n focus: focus as Parameters<typeof runContextualEdit>[0]['focus'],\n instruction,\n workDir: workspace.workDir,\n provider,\n model,\n userId,\n workspace,\n signal: abortController.signal,\n ...(extraProviderConfig !== undefined ? { providerConfig: extraProviderConfig } : {}),\n });\n\n if (!editResult.success) {\n sendSSEEvent(res, {\n type: 'error',\n data: {\n error: editResult.error ?? 'The edit did not change anything.',\n code: 'failed',\n },\n timestamp: Date.now(),\n });\n return;\n }\n\n const rawSchema = workspace.readSchema();\n let composedSchema: OrbitalSchema | null = null;\n if (rawSchema !== null) {\n try {\n composedSchema = JSON.parse(rawSchema) as OrbitalSchema;\n } catch {\n // malformed schema — emit complete without it\n }\n }\n\n sendSSEEvent(res, {\n type: 'complete',\n data: {\n threadId,\n skill: 'rabit',\n workDir: workspace.workDir,\n schemaGenerated: composedSchema !== null,\n appCompiled: false,\n schemaPersisted: false,\n ...(composedSchema !== null ? { schema: composedSchema } : {}),\n ...(workspace.appId !== undefined ? { appId: workspace.appId } : {}),\n },\n timestamp: Date.now(),\n });\n\n if (composedSchema !== null) {\n try {\n await opts.onComplete?.(composedSchema, req);\n } catch {\n // best-effort\n }\n }\n } catch (err: unknown) {\n const isAbort =\n err instanceof Error &&\n (err.name === 'AbortError' || abortController.signal.aborted);\n if (isAbort) {\n sendSSEEvent(res, {\n type: 'cancelled',\n data: { threadId, message: 'Edit cancelled' },\n timestamp: Date.now(),\n });\n } else {\n const message = err instanceof Error ? err.message : String(err);\n sendSSEEvent(res, {\n type: 'error',\n data: { error: message, code: 'runtime' },\n timestamp: Date.now(),\n });\n }\n } finally {\n try {\n unsubscribe();\n } catch {\n // best-effort\n }\n closeSSE(res);\n }\n };\n}\n"]}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { OrbitalSchema, EntityData, EventPayload } from '@almadar/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Public SDK types. Canonical schema / payload types come from `@almadar/core`;
|
|
5
|
+
* the SDK adds the typed event union and HTTP-layer option shapes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Canonical JSON value type — the closure of every value that survives a
|
|
10
|
+
* `JSON.parse(JSON.stringify(x))` round-trip. Used as the JSON-parse output
|
|
11
|
+
* type so we never widen to `unknown` at HTTP boundaries.
|
|
12
|
+
*
|
|
13
|
+
* Mirrors `packages/almadar-agent/src/api-types.ts:25-31`.
|
|
14
|
+
*/
|
|
15
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
16
|
+
[key: string]: JsonValue;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Lifecycle events emitted by the agent during a `generate()` call. Mirrors
|
|
20
|
+
* the SSE event types from
|
|
21
|
+
* `apps/builder/packages/server/src/routes/agent/deepagent.ts` — keep in sync
|
|
22
|
+
* when new events are added on the server.
|
|
23
|
+
*/
|
|
24
|
+
type AgentEvent = {
|
|
25
|
+
type: 'start';
|
|
26
|
+
threadId: string;
|
|
27
|
+
workDir: string;
|
|
28
|
+
} | {
|
|
29
|
+
type: 'plan_committed';
|
|
30
|
+
orbitals: readonly string[];
|
|
31
|
+
} | {
|
|
32
|
+
type: 'orbital_added';
|
|
33
|
+
orbital: string;
|
|
34
|
+
} | {
|
|
35
|
+
type: 'schema_update';
|
|
36
|
+
schema: OrbitalSchema;
|
|
37
|
+
} | {
|
|
38
|
+
type: 'app_created';
|
|
39
|
+
appId: string;
|
|
40
|
+
name: string;
|
|
41
|
+
} | {
|
|
42
|
+
type: 'subagent_start';
|
|
43
|
+
subagent: string;
|
|
44
|
+
} | {
|
|
45
|
+
type: 'subagent_progress';
|
|
46
|
+
subagent: string;
|
|
47
|
+
message: string;
|
|
48
|
+
} | {
|
|
49
|
+
type: 'subagent_complete';
|
|
50
|
+
subagent: string;
|
|
51
|
+
} | {
|
|
52
|
+
type: 'coordinator_decision';
|
|
53
|
+
decision: string;
|
|
54
|
+
} | {
|
|
55
|
+
type: 'complete';
|
|
56
|
+
schema: OrbitalSchema;
|
|
57
|
+
appId?: string;
|
|
58
|
+
} | {
|
|
59
|
+
type: 'error';
|
|
60
|
+
message: string;
|
|
61
|
+
code?: number;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Server-emitted error envelope. `code` maps to the SDK error subclasses:
|
|
65
|
+
* 4001 → ApiKeyError, 4029 → RateLimitedError, 4040 → CatalogOutOfScopeError.
|
|
66
|
+
*/
|
|
67
|
+
interface ApiErrorBody {
|
|
68
|
+
code: number;
|
|
69
|
+
message: string;
|
|
70
|
+
details?: EventPayload;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Async-mode (`generate({ async: true })`) server response. The client polls
|
|
74
|
+
* `statusUrl` until the job resolves.
|
|
75
|
+
*/
|
|
76
|
+
interface AsyncJobHandle {
|
|
77
|
+
jobId: string;
|
|
78
|
+
statusUrl: string;
|
|
79
|
+
}
|
|
80
|
+
interface GenerateOptions {
|
|
81
|
+
prompt: string;
|
|
82
|
+
endUserId?: string;
|
|
83
|
+
appId?: string;
|
|
84
|
+
/** Streaming callback for SSE events. */
|
|
85
|
+
onEvent?: (event: AgentEvent) => void;
|
|
86
|
+
/**
|
|
87
|
+
* When true, server responds with an `AsyncJobHandle` immediately and the
|
|
88
|
+
* client polls. Useful for generations expected to exceed proxy SSE timeouts.
|
|
89
|
+
*/
|
|
90
|
+
async?: boolean;
|
|
91
|
+
}
|
|
92
|
+
interface GenerateResult {
|
|
93
|
+
schema: OrbitalSchema;
|
|
94
|
+
appId?: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Body of a `PUT /api/v1/agent/edit-schema`. Strictly structural; the SDK
|
|
98
|
+
* does not deep-type the patch — that's the server's job. Field types are
|
|
99
|
+
* `EventPayload`-compatible so callers can't sneak in arbitrary objects.
|
|
100
|
+
*/
|
|
101
|
+
interface EditSchemaPatch {
|
|
102
|
+
orbital?: string;
|
|
103
|
+
traitOverrides?: EventPayload;
|
|
104
|
+
config?: EventPayload;
|
|
105
|
+
}
|
|
106
|
+
interface CompileOptions {
|
|
107
|
+
target?: 'express' | 'hono';
|
|
108
|
+
shell?: 'typescript' | 'python' | 'mobile';
|
|
109
|
+
}
|
|
110
|
+
interface CompileResult {
|
|
111
|
+
downloadUrl: string;
|
|
112
|
+
expiresAt: string;
|
|
113
|
+
}
|
|
114
|
+
interface AlmadarClientOptions {
|
|
115
|
+
apiKey: string;
|
|
116
|
+
baseUrl?: string;
|
|
117
|
+
fetch?: typeof fetch;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Props for `<AlmadarApp />` — renders an orbital schema. The runtime mode
|
|
121
|
+
* decides whether effects (persist/fetch/call-service) hit a backend or stay
|
|
122
|
+
* mocked in-browser.
|
|
123
|
+
*/
|
|
124
|
+
interface AlmadarAppProps {
|
|
125
|
+
schema: OrbitalSchema;
|
|
126
|
+
/**
|
|
127
|
+
* - `static`: pure client-side, no server effects. Use with `data`.
|
|
128
|
+
* - `mock` (default): in-browser fake server, faker-seeded if `data` is undefined.
|
|
129
|
+
* - `server`: real backend at `serverUrl`.
|
|
130
|
+
*/
|
|
131
|
+
mode?: 'static' | 'mock' | 'server';
|
|
132
|
+
/** Seed data keyed by entity name (canonical `EntityData` shape). */
|
|
133
|
+
data?: EntityData;
|
|
134
|
+
/** Required when `mode === 'server'`. */
|
|
135
|
+
serverUrl?: string;
|
|
136
|
+
initialPagePath?: string;
|
|
137
|
+
height?: string;
|
|
138
|
+
className?: string;
|
|
139
|
+
theme?: 'copper' | 'wireframe' | 'default';
|
|
140
|
+
}
|
|
141
|
+
interface AlmadarAppRef {
|
|
142
|
+
emit(eventName: string, payload?: EventPayload): void;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export type { AgentEvent as A, CompileOptions as C, EditSchemaPatch as E, GenerateOptions as G, JsonValue as J, AlmadarAppProps as a, AlmadarAppRef as b, AlmadarClientOptions as c, ApiErrorBody as d, AsyncJobHandle as e, CompileResult as f, GenerateResult as g };
|
package/package.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@almadar/sdk",
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
|
+
"description": "Almadar SDK — embed agent-generated orbital schemas in your React app. AlmadarApp component + AlmadarClient HTTP client.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./client": {
|
|
15
|
+
"types": "./dist/client/index.d.ts",
|
|
16
|
+
"import": "./dist/client/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./react": {
|
|
19
|
+
"types": "./dist/react/index.d.ts",
|
|
20
|
+
"import": "./dist/react/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./server": {
|
|
23
|
+
"types": "./dist/server/index.d.ts",
|
|
24
|
+
"import": "./dist/server/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@almadar/core": ">=10",
|
|
34
|
+
"@almadar/runtime": ">=6.13",
|
|
35
|
+
"@almadar/ui": ">=5.32",
|
|
36
|
+
"@almadar-io/rabit": ">=0.1.0",
|
|
37
|
+
"@almadar/workspace": ">=0.1.0",
|
|
38
|
+
"@almadar/server": ">=2.14.0",
|
|
39
|
+
"express": ">=4.0.0",
|
|
40
|
+
"react": ">=18.0.0",
|
|
41
|
+
"react-dom": ">=18.0.0",
|
|
42
|
+
"@almadar/llm": ">=2.24.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependenciesMeta": {
|
|
45
|
+
"@almadar-io/rabit": {
|
|
46
|
+
"optional": true
|
|
47
|
+
},
|
|
48
|
+
"@almadar/workspace": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"@almadar/server": {
|
|
52
|
+
"optional": true
|
|
53
|
+
},
|
|
54
|
+
"express": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"@almadar/llm": {
|
|
58
|
+
"optional": true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@almadar/core": ">=10",
|
|
63
|
+
"@almadar/eslint-plugin": ">=2.7.0",
|
|
64
|
+
"@almadar/runtime": ">=6.13",
|
|
65
|
+
"@almadar/ui": ">=5.32",
|
|
66
|
+
"@almadar-io/rabit": ">=0.1.0",
|
|
67
|
+
"@almadar/workspace": ">=0.1.0",
|
|
68
|
+
"@almadar/server": ">=2.14.0",
|
|
69
|
+
"@testing-library/react": "^16.1.0",
|
|
70
|
+
"@types/express": "^4.17.21",
|
|
71
|
+
"@types/react": "^18.3.12",
|
|
72
|
+
"@types/react-dom": "^18.3.1",
|
|
73
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
74
|
+
"eslint": "10.0.0",
|
|
75
|
+
"express": "^4.21.0",
|
|
76
|
+
"happy-dom": "^15.11.7",
|
|
77
|
+
"react": "^18.3.1",
|
|
78
|
+
"react-dom": "^18.3.1",
|
|
79
|
+
"tsup": "^8.3.5",
|
|
80
|
+
"typescript": "^5.7.0",
|
|
81
|
+
"vitest": "^2.1.0",
|
|
82
|
+
"@almadar/llm": ">=2.24.0"
|
|
83
|
+
},
|
|
84
|
+
"publishConfig": {
|
|
85
|
+
"registry": "https://registry.npmjs.org",
|
|
86
|
+
"access": "public"
|
|
87
|
+
},
|
|
88
|
+
"repository": {
|
|
89
|
+
"type": "git",
|
|
90
|
+
"url": "https://github.com/almadar-io/almadar-sdk.git"
|
|
91
|
+
},
|
|
92
|
+
"license": "BSL-1.1",
|
|
93
|
+
"scripts": {
|
|
94
|
+
"build": "tsup",
|
|
95
|
+
"build:watch": "tsup --watch",
|
|
96
|
+
"lint": "eslint src/",
|
|
97
|
+
"typecheck": "tsc --noEmit",
|
|
98
|
+
"test": "vitest --run"
|
|
99
|
+
}
|
|
100
|
+
}
|