orchajs 0.0.1 → 0.1.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +243 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +86 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/compiler/build-project.d.ts +5 -0
  7. package/dist/compiler/build-project.d.ts.map +1 -0
  8. package/dist/compiler/build-project.js +93 -0
  9. package/dist/compiler/build-project.js.map +1 -0
  10. package/dist/compiler/compile.d.ts +4 -0
  11. package/dist/compiler/compile.d.ts.map +1 -0
  12. package/dist/compiler/compile.js +206 -0
  13. package/dist/compiler/compile.js.map +1 -0
  14. package/dist/errors.d.ts +12 -0
  15. package/dist/errors.d.ts.map +1 -0
  16. package/dist/errors.js +13 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/index.d.ts +6 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +4 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/integrations/esbuild.d.ts +10 -0
  23. package/dist/integrations/esbuild.d.ts.map +1 -0
  24. package/dist/integrations/esbuild.js +22 -0
  25. package/dist/integrations/esbuild.js.map +1 -0
  26. package/dist/orcha.d.ts +3 -0
  27. package/dist/orcha.d.ts.map +1 -0
  28. package/dist/orcha.js +15 -0
  29. package/dist/orcha.js.map +1 -0
  30. package/dist/providers/anthropic.d.ts +30 -0
  31. package/dist/providers/anthropic.d.ts.map +1 -0
  32. package/dist/providers/anthropic.js +158 -0
  33. package/dist/providers/anthropic.js.map +1 -0
  34. package/dist/runtime/actions/context.d.ts +17 -0
  35. package/dist/runtime/actions/context.d.ts.map +1 -0
  36. package/dist/runtime/actions/context.js +45 -0
  37. package/dist/runtime/actions/context.js.map +1 -0
  38. package/dist/runtime/actions/execute.d.ts +10 -0
  39. package/dist/runtime/actions/execute.d.ts.map +1 -0
  40. package/dist/runtime/actions/execute.js +14 -0
  41. package/dist/runtime/actions/execute.js.map +1 -0
  42. package/dist/runtime/actions/native.d.ts +4 -0
  43. package/dist/runtime/actions/native.d.ts.map +1 -0
  44. package/dist/runtime/actions/native.js +27 -0
  45. package/dist/runtime/actions/native.js.map +1 -0
  46. package/dist/runtime/actions/sandbox.d.ts +7 -0
  47. package/dist/runtime/actions/sandbox.d.ts.map +1 -0
  48. package/dist/runtime/actions/sandbox.js +117 -0
  49. package/dist/runtime/actions/sandbox.js.map +1 -0
  50. package/dist/runtime/agent.d.ts +18 -0
  51. package/dist/runtime/agent.d.ts.map +1 -0
  52. package/dist/runtime/agent.js +1113 -0
  53. package/dist/runtime/agent.js.map +1 -0
  54. package/dist/runtime/create-orcha.d.ts +11 -0
  55. package/dist/runtime/create-orcha.d.ts.map +1 -0
  56. package/dist/runtime/create-orcha.js +83 -0
  57. package/dist/runtime/create-orcha.js.map +1 -0
  58. package/dist/runtime/session-events.d.ts +13 -0
  59. package/dist/runtime/session-events.d.ts.map +1 -0
  60. package/dist/runtime/session-events.js +59 -0
  61. package/dist/runtime/session-events.js.map +1 -0
  62. package/dist/runtime/structured-output.d.ts +3 -0
  63. package/dist/runtime/structured-output.d.ts.map +1 -0
  64. package/dist/runtime/structured-output.js +126 -0
  65. package/dist/runtime/structured-output.js.map +1 -0
  66. package/dist/storage/browser-indexeddb.d.ts +21 -0
  67. package/dist/storage/browser-indexeddb.d.ts.map +1 -0
  68. package/dist/storage/browser-indexeddb.js +26 -0
  69. package/dist/storage/browser-indexeddb.js.map +1 -0
  70. package/dist/storage/edge-store.d.ts +20 -0
  71. package/dist/storage/edge-store.d.ts.map +1 -0
  72. package/dist/storage/edge-store.js +25 -0
  73. package/dist/storage/edge-store.js.map +1 -0
  74. package/dist/storage/node-jsonl.d.ts +10 -0
  75. package/dist/storage/node-jsonl.d.ts.map +1 -0
  76. package/dist/storage/node-jsonl.js +80 -0
  77. package/dist/storage/node-jsonl.js.map +1 -0
  78. package/dist/storage/react-native-jsonl.d.ts +21 -0
  79. package/dist/storage/react-native-jsonl.d.ts.map +1 -0
  80. package/dist/storage/react-native-jsonl.js +26 -0
  81. package/dist/storage/react-native-jsonl.js.map +1 -0
  82. package/dist/types.d.ts +216 -0
  83. package/dist/types.d.ts.map +1 -0
  84. package/dist/types.js +2 -0
  85. package/dist/types.js.map +1 -0
  86. package/package.json +57 -1
package/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # OrchaJS
2
+
3
+ **An agent is a folder.** OrchaJS is a filesystem-convention framework for building AI agents in JavaScript — no orchestration graph, no client to instantiate, no export step. It's a library, not a platform: add it to Next.js, React, React Native, Express, NestJS, or plain Node, the way you'd add Prisma or Zod.
4
+
5
+ > Early and moving fast. Not yet accepting external contributions — see [Status](#status) below.
6
+
7
+ ---
8
+
9
+ ## Why
10
+
11
+ Most agent frameworks or platforms ask you to trust a black box: the real logic lives inside someone else's runtime, and what you get to "own" is a copy or an export of it. OrchaJS removes that gap by making the file tree the actual source of truth — there's no internal state that isn't also a file you can open, edit, and run yourself.
12
+
13
+ Read the full concept: [`docs/concept.md`](./docs/concept.md)
14
+
15
+ ---
16
+
17
+ ## The convention
18
+
19
+ ```
20
+ /agentname
21
+ index.js | index.json → provider, model, generation config, output schema
22
+ instructions.md → required base agent instructions
23
+ /skills
24
+ /skillname
25
+ index.json → { name, description, triggers }
26
+ instructions.md → procedural knowledge, lazy-loaded into context
27
+ /actions
28
+ /actionname
29
+ index.json → definition, schemas, and execution location
30
+ index.js → executable code for local actions only
31
+ /guardrails → input/output policy
32
+ /tests → test cases, auto-run before every release
33
+ /evaluations → metrics each run is judged against
34
+ ```
35
+
36
+ Placement determines behavior. No manual registration of tools, skills, or routes.
37
+
38
+ ---
39
+
40
+ ## Model Action Protocol
41
+
42
+ What a model can do lives in `/actions`. Every action has `index.json`; local
43
+ actions additionally have `index.js`.
44
+
45
+ ```
46
+ actions/
47
+ send-refund/
48
+ index.json // the definition
49
+ index.js // the code
50
+ ```
51
+
52
+ `index.json` tells the model what the action is, where it executes, and its
53
+ input/output contracts:
54
+
55
+ ```json
56
+ {
57
+ "name": "request_refund_approval",
58
+ "description": "Ask the client application to approve a refund.",
59
+ "execution": "client",
60
+ "parameters": {
61
+ "type": "object",
62
+ "properties": {
63
+ "orderId": { "type": "string" },
64
+ "amount": { "type": "number" }
65
+ },
66
+ "required": ["orderId", "amount"]
67
+ },
68
+ "outputSchema": {
69
+ "type": "object",
70
+ "properties": {
71
+ "approved": { "type": "boolean" }
72
+ },
73
+ "required": ["approved"]
74
+ }
75
+ }
76
+ ```
77
+
78
+ Client actions pause the durable run. The application advertises only the
79
+ actions available on that client, executes the requested call, then resumes:
80
+
81
+ ```js
82
+ const paused = await orcha.invoiceBot.run({
83
+ content: "Refund order 123",
84
+ clientCapabilities: orcha.invoiceBot.clientTools
85
+ }).result;
86
+
87
+ if (paused.status === "waiting_for_client_action") {
88
+ const completed = await orcha.invoiceBot.resume(paused.sessionId, {
89
+ toolResults: paused.clientToolCalls.map((call) => ({
90
+ callId: call.callId,
91
+ output: { approved: true }
92
+ }))
93
+ }).result;
94
+ }
95
+ ```
96
+
97
+ Definitions are compiled from the filesystem and are not submitted again to
98
+ `resume()`. Requests and results are persisted in the session JSONL.
99
+
100
+ Local actions export their implementation from `index.js` and execute
101
+ automatically inside the model tool loop:
102
+
103
+ ```js
104
+ export default async function sendRefund(parameters, context) {
105
+ return {
106
+ refunded: true,
107
+ orderId: parameters.orderId,
108
+ idempotencyKey: context.idempotencyKey,
109
+ };
110
+ }
111
+ ```
112
+
113
+ Projects with local actions must explicitly choose their runtime:
114
+
115
+ ```js
116
+ orcha.init({
117
+ actions: {
118
+ runtime: "sandbox", // QuickJS WASM
119
+ env: {
120
+ REFUND_API_KEY: process.env.REFUND_API_KEY,
121
+ },
122
+ },
123
+ // providers and agents...
124
+ });
125
+ ```
126
+
127
+ Use `"native"` to execute compiled action JavaScript directly without the
128
+ QuickJS dependency in the production bundle. Native execution is trusted code
129
+ with full host privileges; declared permissions are only securely enforced by
130
+ the sandbox runtime. Native timeouts can reject asynchronous work but cannot
131
+ interrupt a synchronous infinite loop.
132
+
133
+ ---
134
+
135
+ ## Quick start
136
+
137
+ ```bash
138
+ npm install orchajs
139
+ npx orcha init
140
+ ```
141
+
142
+ ```js
143
+ // Import the consumer registry once from the application entrypoint.
144
+ import './orcha/index.js';
145
+ import { orcha } from 'orchajs';
146
+
147
+ const execution = orcha.exampleAgent.run({
148
+ content: 'Help me understand this invoice'
149
+ });
150
+ const result = await execution.result;
151
+
152
+ // Every later conversational turn uses the returned sessionId.
153
+ const followUp = await orcha.exampleAgent.resume(result.sessionId, {
154
+ content: 'Now summarize it in one sentence'
155
+ }).result;
156
+ ```
157
+
158
+ Registered agents are exposed as `orcha.<agentName>`. The first implementation
159
+ supports durable Node.js runs backed by `.orcha/sessions/<sessionId>.jsonl`.
160
+ Client-action pause/resume is supported; local actions and streaming follow.
161
+ `run()` always starts a new session; `resume()` continues one with either a new
162
+ message or pending client tool results.
163
+
164
+ Both methods accept text shorthand:
165
+
166
+ ```js
167
+ const first = await orcha.exampleAgent.run("Start").result;
168
+ const second = await orcha.exampleAgent.resume(
169
+ first.sessionId,
170
+ "Continue",
171
+ ).result;
172
+ ```
173
+
174
+ Canonical input uses a multimodal `content` array:
175
+
176
+ ```js
177
+ const result = await orcha.exampleAgent.run({
178
+ content: [
179
+ { type: "text", text: "Summarize this document" },
180
+ {
181
+ type: "url",
182
+ mimeType: "application/pdf",
183
+ fileUri: "https://example.com/report.pdf",
184
+ },
185
+ ],
186
+ name: "Customer report",
187
+ metadata: { customerId: "cus_123" },
188
+ variables: { CUSTOMER_NAME: "Acme" },
189
+ }).result;
190
+ ```
191
+
192
+ Prompt variables replace `{{CUSTOMER_NAME}}` placeholders in
193
+ `instructions.md`. They are fixed when the session is created and persisted
194
+ for deterministic continuation. Do not put secrets in prompt variables; use
195
+ provider or action environment configuration for secrets.
196
+
197
+ Sessions are managed through the same registered agent:
198
+
199
+ ```js
200
+ await orcha.exampleAgent.get(sessionId);
201
+ await orcha.exampleAgent.history(sessionId, { page: 1, pageSize: 50 });
202
+ await orcha.exampleAgent.list({
203
+ metadata: { customerId: "cus_123" },
204
+ page: 1,
205
+ pageSize: 20,
206
+ });
207
+ await orcha.exampleAgent.update(sessionId, {
208
+ name: "September invoice",
209
+ metadata: { approved: true },
210
+ });
211
+ ```
212
+
213
+ For esbuild production applications, add `orchaPlugin()` from
214
+ `orchajs/esbuild` to the existing build. It compiles the registry and replaces
215
+ unchanged `orchajs` imports with the self-contained generated runtime. The
216
+ application continues to use its normal `npm run build` command.
217
+
218
+ ---
219
+
220
+ ## What's in this repo right now
221
+
222
+ - [x] Registry compiler + `orcha build`
223
+ - [x] Model Action Protocol — client actions and opt-in native/sandboxed local actions
224
+ - [ ] Compiler — one provider, correct tool calls + streaming
225
+ - [x] Stateful sessions — Node JSONL replay and client-action pause/resume
226
+ - [ ] `orcha.run()` one-shot entry point
227
+ - [ ] CLI (`orcha init`, `orcha build`, `orcha dev`) + example agents
228
+
229
+ See [`ROADMAP.md`](./ROADMAP.md) for what's coming after — a second provider, an evaluations runner, OpenTelemetry tracing, MCP interop adapters, and remote session storage are all deliberately out of scope for the first release.
230
+
231
+ ---
232
+
233
+ ## Status
234
+
235
+ This project is being built in the open by a solo maintainer. It's not yet stable enough to take contributions productively — the core convention and API are still moving. `CONTRIBUTING.md` will open up once the shape settles.
236
+
237
+ In the meantime: [star the repo](.) to follow along, open an issue if you hit something worth flagging, or watch for weekly build-in-public updates on [X/Twitter](.).
238
+
239
+ ---
240
+
241
+ ## License
242
+
243
+ [MIT](./LICENSE)
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from "node:fs";
3
+ import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
4
+ import { dirname, resolve } from "node:path";
5
+ import { buildProject } from "./compiler/build-project.js";
6
+ const command = process.argv[2];
7
+ try {
8
+ if (command === "init") {
9
+ await initializeProject(process.cwd());
10
+ }
11
+ else if (command === "build") {
12
+ const outputPath = await buildProject({ projectRoot: process.cwd() });
13
+ console.log(`Built ${outputPath}`);
14
+ }
15
+ else {
16
+ printUsage();
17
+ process.exitCode = command ? 1 : 0;
18
+ }
19
+ }
20
+ catch (error) {
21
+ console.error(error instanceof Error ? error.message : String(error));
22
+ process.exitCode = 1;
23
+ }
24
+ async function initializeProject(projectRoot) {
25
+ const files = new Map([
26
+ [
27
+ "orcha/exampleAgent/index.json",
28
+ `${JSON.stringify({
29
+ provider: "anthropic",
30
+ model: "claude-sonnet-4-6",
31
+ region: "provider_managed",
32
+ maxTokens: 1024,
33
+ reasoningLevel: "disabled",
34
+ outputType: "text",
35
+ }, null, 2)}\n`,
36
+ ],
37
+ [
38
+ "orcha/exampleAgent/instructions.md",
39
+ "You are a concise and helpful assistant.\n",
40
+ ],
41
+ [
42
+ "orcha/index.ts",
43
+ [
44
+ 'import { orcha } from "orchajs";',
45
+ "",
46
+ "orcha.init({",
47
+ " providers: {",
48
+ " anthropic: process.env.ANTHROPIC_API_KEY ?? \"\",",
49
+ " },",
50
+ " agents: {",
51
+ " exampleAgent: \"./exampleAgent\",",
52
+ " },",
53
+ "});",
54
+ "",
55
+ ].join("\n"),
56
+ ],
57
+ ]);
58
+ for (const [relativePath, contents] of files) {
59
+ const path = resolve(projectRoot, relativePath);
60
+ if (existsSync(path)) {
61
+ console.log(`Skipped existing ${relativePath}`);
62
+ continue;
63
+ }
64
+ await mkdir(dirname(path), { recursive: true });
65
+ await writeFile(path, contents, "utf8");
66
+ console.log(`Created ${relativePath}`);
67
+ }
68
+ await ensureGitignore(projectRoot);
69
+ console.log('\nImport "./orcha/index.js" once from your application entrypoint, then run your existing development command.');
70
+ }
71
+ async function ensureGitignore(projectRoot) {
72
+ const path = resolve(projectRoot, ".gitignore");
73
+ const entry = ".orcha/";
74
+ const current = existsSync(path) ? await readFile(path, "utf8") : "";
75
+ const entries = current.split(/\r?\n/).map((line) => line.trim());
76
+ if (entries.includes(entry)) {
77
+ return;
78
+ }
79
+ const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
80
+ await appendFile(path, `${prefix}${entry}\n`, "utf8");
81
+ console.log("Updated .gitignore");
82
+ }
83
+ function printUsage() {
84
+ console.log(["Usage: orcha <command>", "", "Commands:", " init", " build"].join("\n"));
85
+ }
86
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface BuildProjectOptions {
2
+ projectRoot?: string;
3
+ }
4
+ export declare function buildProject(options?: BuildProjectOptions): Promise<string>;
5
+ //# sourceMappingURL=build-project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-project.d.ts","sourceRoot":"","sources":["../../src/compiler/build-project.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,YAAY,CAChC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,MAAM,CAAC,CAoGjB"}
@@ -0,0 +1,93 @@
1
+ import { existsSync } from "node:fs";
2
+ import { mkdir, rm, writeFile } from "node:fs/promises";
3
+ import { dirname, resolve } from "node:path";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+ import { build as bundleEntry } from "esbuild";
6
+ import { orcha } from "../orcha.js";
7
+ export async function buildProject(options = {}) {
8
+ const projectRoot = resolve(options.projectRoot ?? process.cwd());
9
+ const registryPath = resolve(projectRoot, "orcha/index.ts");
10
+ if (!existsSync(registryPath)) {
11
+ throw new Error('Missing "orcha/index.ts". Run "orcha init" first.');
12
+ }
13
+ const temporaryDirectory = resolve(projectRoot, ".orcha/.build");
14
+ const registryBundlePath = resolve(temporaryDirectory, "registry.mjs");
15
+ const productionEntryPath = resolve(temporaryDirectory, "production-entry.mjs");
16
+ const outputPath = resolve(projectRoot, ".orcha/dist/bundle.js");
17
+ await mkdir(temporaryDirectory, { recursive: true });
18
+ await mkdir(dirname(outputPath), { recursive: true });
19
+ try {
20
+ await bundleEntry({
21
+ entryPoints: [registryPath],
22
+ outfile: registryBundlePath,
23
+ bundle: true,
24
+ format: "esm",
25
+ platform: "node",
26
+ target: "node20",
27
+ packages: "external",
28
+ logLevel: "silent",
29
+ });
30
+ const previousCompiling = process.env.ORCHA_COMPILING;
31
+ const previousProjectRoot = process.env.ORCHA_PROJECT_ROOT;
32
+ process.env.ORCHA_COMPILING = "1";
33
+ process.env.ORCHA_PROJECT_ROOT = projectRoot;
34
+ try {
35
+ await import(`${pathToFileURL(registryBundlePath).href}?time=${Date.now()}`);
36
+ }
37
+ finally {
38
+ if (previousCompiling === undefined) {
39
+ delete process.env.ORCHA_COMPILING;
40
+ }
41
+ else {
42
+ process.env.ORCHA_COMPILING = previousCompiling;
43
+ }
44
+ if (previousProjectRoot === undefined) {
45
+ delete process.env.ORCHA_PROJECT_ROOT;
46
+ }
47
+ else {
48
+ process.env.ORCHA_PROJECT_ROOT = previousProjectRoot;
49
+ }
50
+ }
51
+ const compiledBundle = orcha.getCompiledBundle();
52
+ const runtimeFactoryPath = resolve(dirname(fileURLToPath(import.meta.url)), "../runtime/create-orcha.js").replaceAll("\\", "/");
53
+ await writeFile(productionEntryPath, [
54
+ `import { createOrcha } from ${JSON.stringify(runtimeFactoryPath)};`,
55
+ `const compiledBundle = ${JSON.stringify(compiledBundle)};`,
56
+ "export const orcha = createOrcha(() => compiledBundle);",
57
+ "export default orcha;",
58
+ "",
59
+ ].join("\n"), "utf8");
60
+ await bundleEntry({
61
+ entryPoints: [productionEntryPath],
62
+ outfile: outputPath,
63
+ bundle: true,
64
+ format: "esm",
65
+ platform: "node",
66
+ target: "node20",
67
+ minify: true,
68
+ legalComments: "none",
69
+ define: {
70
+ "process.env.ORCHA_INCLUDE_SANDBOX": JSON.stringify(compiledBundle.actionRuntime === "sandbox" ? "1" : "0"),
71
+ },
72
+ ...(compiledBundle.actionRuntime === "sandbox"
73
+ ? {
74
+ banner: {
75
+ js: [
76
+ 'import { createRequire as __orchaCreateRequire } from "node:module";',
77
+ "const require = __orchaCreateRequire(import.meta.url);",
78
+ ].join("\n"),
79
+ },
80
+ }
81
+ : {}),
82
+ logLevel: "silent",
83
+ });
84
+ return outputPath;
85
+ }
86
+ finally {
87
+ await rm(temporaryDirectory, {
88
+ recursive: true,
89
+ force: true,
90
+ });
91
+ }
92
+ }
93
+ //# sourceMappingURL=build-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-project.js","sourceRoot":"","sources":["../../src/compiler/build-project.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { CompiledBundle } from "../types.js";
2
+ export declare function compileRegistry(registrations: Record<string, string>, registryRoot: string, actionRuntime?: "native" | "sandbox"): CompiledBundle;
3
+ export declare function serializeBundle(bundle: CompiledBundle): string;
4
+ //# sourceMappingURL=compile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compiler/compile.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAKV,cAAc,EAEf,MAAM,aAAa,CAAC;AAIrB,wBAAgB,eAAe,CAC7B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACrC,YAAY,EAAE,MAAM,EACpB,aAAa,CAAC,EAAE,QAAQ,GAAG,SAAS,GACnC,cAAc,CAgHhB;AAmKD,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAO9D"}
@@ -0,0 +1,206 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { buildSync } from "esbuild";
5
+ const SUPPORTED_PROVIDERS = new Set(["anthropic"]);
6
+ export function compileRegistry(registrations, registryRoot, actionRuntime) {
7
+ if (!registrations ||
8
+ typeof registrations !== "object" ||
9
+ Array.isArray(registrations)) {
10
+ throw new TypeError('orcha.init() requires an "agents" object of registered folder paths.');
11
+ }
12
+ const agents = {};
13
+ for (const [name, registeredPath] of Object.entries(registrations)) {
14
+ if (!name.trim()) {
15
+ throw new Error("Registered agent names cannot be empty.");
16
+ }
17
+ if (typeof registeredPath !== "string" || !registeredPath.trim()) {
18
+ throw new Error(`Agent "${name}" must register a folder path.`);
19
+ }
20
+ const sourceDirectory = resolve(registryRoot, registeredPath);
21
+ const configPath = resolve(sourceDirectory, "index.json");
22
+ let configuration;
23
+ try {
24
+ configuration = JSON.parse(readFileSync(configPath, "utf8"));
25
+ }
26
+ catch (error) {
27
+ throw new Error(`Agent "${name}" is missing a valid index.json at ${configPath}.`, { cause: error });
28
+ }
29
+ if (!SUPPORTED_PROVIDERS.has(configuration.provider)) {
30
+ throw new Error(`Agent "${name}" uses unsupported provider "${configuration.provider}".`);
31
+ }
32
+ if (!configuration.model?.trim()) {
33
+ throw new Error(`Agent "${name}" must configure a model.`);
34
+ }
35
+ validateNumber(name, "maxTokens", configuration.maxTokens, {
36
+ integer: true,
37
+ minimum: 1,
38
+ });
39
+ if (configuration.outputType &&
40
+ !["text", "json", "image", "audio"].includes(configuration.outputType)) {
41
+ throw new Error(`Agent "${name}" has an invalid outputType.`);
42
+ }
43
+ if (configuration.reasoningLevel &&
44
+ !["disabled", "low", "medium", "high"].includes(configuration.reasoningLevel)) {
45
+ throw new Error(`Agent "${name}" has an invalid reasoningLevel.`);
46
+ }
47
+ if (!["text", "json"].includes(configuration.outputType ?? "text")) {
48
+ throw new Error(`Agent "${name}" outputType "${configuration.outputType}" is not implemented yet.`);
49
+ }
50
+ if (configuration.outputType === "json" &&
51
+ (!configuration.outputSchema ||
52
+ typeof configuration.outputSchema !== "object")) {
53
+ throw new Error(`Agent "${name}" must configure outputSchema when outputType is "json".`);
54
+ }
55
+ const instructionsPath = resolve(sourceDirectory, "instructions.md");
56
+ let systemPrompt;
57
+ try {
58
+ systemPrompt = readFileSync(instructionsPath, "utf8").trim();
59
+ }
60
+ catch (error) {
61
+ throw new Error(`Agent "${name}" is missing required instructions.md at ${instructionsPath}.`, { cause: error });
62
+ }
63
+ if (!systemPrompt) {
64
+ throw new Error(`Agent "${name}" instructions.md cannot be empty.`);
65
+ }
66
+ agents[name] = Object.freeze({
67
+ name,
68
+ provider: configuration.provider,
69
+ model: configuration.model,
70
+ systemPrompt,
71
+ region: configuration.region,
72
+ maxTokens: configuration.maxTokens,
73
+ reasoningLevel: configuration.reasoningLevel ?? "disabled",
74
+ outputType: configuration.outputType ?? "text",
75
+ outputSchema: configuration.outputSchema,
76
+ actions: compileActions(name, sourceDirectory),
77
+ });
78
+ }
79
+ if (Object.keys(agents).length === 0) {
80
+ throw new Error("At least one agent must be registered.");
81
+ }
82
+ return Object.freeze({
83
+ schemaVersion: 1,
84
+ actionRuntime,
85
+ agents: Object.freeze(agents),
86
+ });
87
+ }
88
+ function compileActions(agentName, sourceDirectory) {
89
+ const actionsDirectory = resolve(sourceDirectory, "actions");
90
+ if (!existsSync(actionsDirectory)) {
91
+ return {};
92
+ }
93
+ const actions = {};
94
+ for (const entry of readdirSync(actionsDirectory, { withFileTypes: true })) {
95
+ if (!entry.isDirectory()) {
96
+ continue;
97
+ }
98
+ const configurationPath = resolve(actionsDirectory, entry.name, "index.json");
99
+ let configuration;
100
+ try {
101
+ configuration = JSON.parse(readFileSync(configurationPath, "utf8"));
102
+ }
103
+ catch (error) {
104
+ throw new Error(`Action "${agentName}/${entry.name}" is missing a valid index.json.`, { cause: error });
105
+ }
106
+ if (!configuration.name?.trim() || !configuration.description?.trim()) {
107
+ throw new Error(`Action "${agentName}/${entry.name}" requires name and description.`);
108
+ }
109
+ if (!/^[a-zA-Z0-9_-]{1,64}$/.test(configuration.name)) {
110
+ throw new Error(`Action "${agentName}/${entry.name}" has an invalid model-facing name.`);
111
+ }
112
+ if (!["client", "local"].includes(configuration.execution)) {
113
+ throw new Error(`Action "${agentName}/${entry.name}" has invalid execution "${configuration.execution}".`);
114
+ }
115
+ if (!configuration.parameters ||
116
+ typeof configuration.parameters !== "object" ||
117
+ Array.isArray(configuration.parameters)) {
118
+ throw new Error(`Action "${agentName}/${entry.name}" requires a parameters JSON Schema.`);
119
+ }
120
+ if (configuration.outputSchema !== undefined &&
121
+ (typeof configuration.outputSchema !== "object" ||
122
+ configuration.outputSchema === null ||
123
+ Array.isArray(configuration.outputSchema))) {
124
+ throw new Error(`Action "${agentName}/${entry.name}" has an invalid outputSchema.`);
125
+ }
126
+ validateNumber(`${agentName}/${entry.name}`, "timeoutMs", configuration.timeoutMs, { integer: true, minimum: 1, maximum: 120_000 });
127
+ if (configuration.permissions?.env !== undefined &&
128
+ !Array.isArray(configuration.permissions.env)) {
129
+ throw new Error(`Action "${agentName}/${entry.name}" permissions.env must be an array.`);
130
+ }
131
+ if (configuration.permissions?.network !== undefined &&
132
+ !Array.isArray(configuration.permissions.network)) {
133
+ throw new Error(`Action "${agentName}/${entry.name}" permissions.network must be an array.`);
134
+ }
135
+ for (const permission of [
136
+ ...(configuration.permissions?.env ?? []),
137
+ ...(configuration.permissions?.network ?? []),
138
+ ]) {
139
+ if (typeof permission !== "string" || !permission.trim()) {
140
+ throw new Error(`Action "${agentName}/${entry.name}" has an invalid permission.`);
141
+ }
142
+ }
143
+ if (actions[configuration.name]) {
144
+ throw new Error(`Agent "${agentName}" has duplicate action name "${configuration.name}".`);
145
+ }
146
+ const compiledSource = configuration.execution === "local"
147
+ ? compileLocalAction(agentName, entry.name, actionsDirectory)
148
+ : undefined;
149
+ actions[configuration.name] = Object.freeze({
150
+ ...configuration,
151
+ directoryName: entry.name,
152
+ ...compiledSource,
153
+ });
154
+ }
155
+ return Object.freeze(actions);
156
+ }
157
+ function compileLocalAction(agentName, directoryName, actionsDirectory) {
158
+ const entryPath = resolve(actionsDirectory, directoryName, "index.js");
159
+ if (!existsSync(entryPath)) {
160
+ throw new Error(`Local action "${agentName}/${directoryName}" requires index.js.`);
161
+ }
162
+ let output;
163
+ try {
164
+ const result = buildSync({
165
+ entryPoints: [entryPath],
166
+ bundle: true,
167
+ write: false,
168
+ format: "iife",
169
+ globalName: "__orchaActionModule",
170
+ platform: "neutral",
171
+ target: "es2022",
172
+ logLevel: "silent",
173
+ });
174
+ output = result.outputFiles[0]?.text ?? "";
175
+ }
176
+ catch (error) {
177
+ throw new Error(`Local action "${agentName}/${directoryName}" could not be bundled.`, { cause: error });
178
+ }
179
+ if (!output.includes("__orchaActionModule")) {
180
+ throw new Error(`Local action "${agentName}/${directoryName}" must export a default function.`);
181
+ }
182
+ return {
183
+ source: output,
184
+ sourceHash: createHash("sha256").update(output).digest("hex"),
185
+ };
186
+ }
187
+ export function serializeBundle(bundle) {
188
+ return [
189
+ "// Generated by OrchaJS. Do not edit manually.",
190
+ `export const bundle = ${JSON.stringify(bundle, null, 2)};`,
191
+ "export default bundle;",
192
+ "",
193
+ ].join("\n");
194
+ }
195
+ function validateNumber(agentName, field, value, constraints) {
196
+ if (value === undefined) {
197
+ return;
198
+ }
199
+ if (!Number.isFinite(value) ||
200
+ (constraints.integer && !Number.isInteger(value)) ||
201
+ (constraints.minimum !== undefined && value < constraints.minimum) ||
202
+ (constraints.maximum !== undefined && value > constraints.maximum)) {
203
+ throw new Error(`Agent "${agentName}" has an invalid ${field}.`);
204
+ }
205
+ }
206
+ //# sourceMappingURL=compile.js.map