orchajs 0.20.3 → 0.21.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 (96) hide show
  1. package/README.md +103 -0
  2. package/dist/bin.d.ts +2 -0
  3. package/dist/bin.js +13 -0
  4. package/dist/browser.d.ts +2 -0
  5. package/dist/browser.js +12 -0
  6. package/dist/cli.js +35 -9
  7. package/dist/compiler/build-project.d.ts +1 -0
  8. package/dist/compiler/build-project.js +75 -8
  9. package/dist/compiler/compile.d.ts +1 -1
  10. package/dist/compiler/compile.js +11 -9
  11. package/dist/file-content.js +42 -6
  12. package/dist/index.d.ts +1 -5
  13. package/dist/index.js +1 -2
  14. package/dist/integrations/esbuild.js +5 -2
  15. package/dist/integrations/expo.d.ts +1 -0
  16. package/dist/integrations/expo.js +1 -0
  17. package/dist/integrations/metro.d.ts +15 -0
  18. package/dist/integrations/metro.js +25 -0
  19. package/dist/integrations/next.d.ts +23 -0
  20. package/dist/integrations/next.js +53 -0
  21. package/dist/integrations/runtime-build.d.ts +4 -0
  22. package/dist/integrations/runtime-build.js +32 -0
  23. package/dist/integrations/vite.d.ts +23 -0
  24. package/dist/integrations/vite.js +32 -0
  25. package/dist/integrations/webpack.d.ts +24 -0
  26. package/dist/integrations/webpack.js +21 -0
  27. package/dist/orcha.js +17 -8
  28. package/dist/playground/server.js +57 -7
  29. package/dist/project-loader.js +3 -0
  30. package/dist/providers/browser.d.ts +2 -0
  31. package/dist/providers/browser.js +20 -0
  32. package/dist/react-native.d.ts +2 -0
  33. package/dist/react-native.js +12 -0
  34. package/dist/runtime/actions/browser-native.d.ts +3 -0
  35. package/dist/runtime/actions/browser-native.js +28 -0
  36. package/dist/runtime/actions/execute.d.ts +7 -0
  37. package/dist/runtime/actions/execute.js +9 -2
  38. package/dist/runtime/agent.d.ts +1 -0
  39. package/dist/runtime/agent.js +8 -5
  40. package/dist/runtime/compiler-hook.d.ts +5 -0
  41. package/dist/runtime/compiler-hook.js +8 -0
  42. package/dist/runtime/create-orcha.d.ts +2 -1
  43. package/dist/runtime/create-orcha.js +15 -19
  44. package/dist/runtime/platform-browser.d.ts +2 -0
  45. package/dist/runtime/platform-browser.js +15 -0
  46. package/dist/runtime/platform-node.d.ts +2 -0
  47. package/dist/runtime/platform-node.js +31 -0
  48. package/dist/runtime/platform-react-native.d.ts +2 -0
  49. package/dist/runtime/platform-react-native.js +15 -0
  50. package/dist/runtime/platform.d.ts +15 -0
  51. package/dist/runtime/platform.js +1 -0
  52. package/dist/runtime/random-id.d.ts +1 -0
  53. package/dist/runtime/random-id.js +26 -0
  54. package/dist/runtime-entry.d.ts +5 -0
  55. package/dist/runtime-entry.js +2 -0
  56. package/dist/storage/browser-indexeddb.d.ts +7 -16
  57. package/dist/storage/browser-indexeddb.js +102 -19
  58. package/dist/storage/react-native-jsonl.d.ts +7 -16
  59. package/dist/storage/react-native-jsonl.js +65 -19
  60. package/dist/types.d.ts +3 -1
  61. package/dist-cjs/browser.js +48 -0
  62. package/dist-cjs/compiler/build-project.js +97 -8
  63. package/dist-cjs/compiler/compile.js +17 -9
  64. package/dist-cjs/file-content.js +42 -7
  65. package/dist-cjs/index.js +4 -9
  66. package/dist-cjs/integrations/esbuild.js +6 -2
  67. package/dist-cjs/integrations/expo.js +29 -0
  68. package/dist-cjs/integrations/metro.js +51 -0
  69. package/dist-cjs/integrations/next.js +75 -0
  70. package/dist-cjs/integrations/runtime-build.js +70 -0
  71. package/dist-cjs/integrations/vite.js +57 -0
  72. package/dist-cjs/integrations/webpack.js +51 -0
  73. package/dist-cjs/orcha.js +17 -12
  74. package/dist-cjs/playground/server.js +62 -9
  75. package/dist-cjs/project-loader.js +10 -0
  76. package/dist-cjs/providers/browser.js +61 -0
  77. package/dist-cjs/react-native.js +48 -0
  78. package/dist-cjs/runtime/actions/browser-native.js +68 -0
  79. package/dist-cjs/runtime/actions/execute.js +12 -2
  80. package/dist-cjs/runtime/agent.js +8 -6
  81. package/dist-cjs/runtime/compiler-hook.js +37 -0
  82. package/dist-cjs/runtime/create-orcha.js +18 -21
  83. package/dist-cjs/runtime/platform-browser.js +48 -0
  84. package/dist-cjs/runtime/platform-node.js +59 -0
  85. package/dist-cjs/runtime/platform-react-native.js +45 -0
  86. package/dist-cjs/runtime/platform.js +17 -0
  87. package/dist-cjs/runtime/random-id.js +55 -0
  88. package/dist-cjs/runtime-entry.js +34 -0
  89. package/dist-cjs/storage/browser-indexeddb.js +102 -5
  90. package/dist-cjs/storage/react-native-jsonl.js +73 -5
  91. package/dist-cjs/types/react-native-async-storage.d.js +2 -0
  92. package/package.json +69 -9
  93. package/dist/playground/public/app.css +0 -1
  94. package/dist/playground/public/app.js +0 -31
  95. package/dist/playground/public/index.html +0 -15
  96. package/dist/playground/public/orcha-logo.svg +0 -4
package/README.md CHANGED
@@ -50,6 +50,109 @@ The Google GenAI and Vertex AI adapters use Google's current SDK and require
50
50
  Node.js 20 or newer. On Node.js 18, the rest of Orcha—including Amazon
51
51
  Bedrock—remains available.
52
52
 
53
+ Compiler and playground packages are optional development dependencies. Apps
54
+ created with `create-orcha` include them automatically. Existing projects that
55
+ use the CLI or a bundler integration should install them explicitly:
56
+
57
+ ```bash
58
+ npm install --save-dev esbuild chokidar dotenv
59
+ ```
60
+
61
+ The local playground is also development-only:
62
+
63
+ ```bash
64
+ npm install --save-dev @orchajs/playground-ui
65
+ ```
66
+
67
+ ## React, Next.js, and React Native
68
+
69
+ Application code always imports the same package:
70
+
71
+ ```ts
72
+ import { orcha } from "orchajs";
73
+ ```
74
+
75
+ The framework integration compiles the filesystem registry ahead of time and
76
+ redirects that unchanged import to a small, target-specific runtime. Compiler,
77
+ filesystem, playground, and unused provider code are not included in the
78
+ customer bundle. Provider adapters are selected from the compiled registry, so
79
+ using OpenAI does not include Anthropic, Google, Bedrock, or Vertex AI code.
80
+
81
+ For React with Vite:
82
+
83
+ ```ts
84
+ // vite.config.ts
85
+ import { defineConfig } from "vite";
86
+ import react from "@vitejs/plugin-react";
87
+ import { orchaVitePlugin } from "orchajs/vite";
88
+
89
+ export default defineConfig({
90
+ plugins: [orchaVitePlugin(), react()],
91
+ });
92
+ ```
93
+
94
+ Webpack-based React applications use the equivalent plugin:
95
+
96
+ ```js
97
+ const { OrchaWebpackPlugin } = require("orchajs/webpack");
98
+
99
+ const orcha = new OrchaWebpackPlugin();
100
+ module.exports = {
101
+ resolve: { alias: { "orchajs$": orcha.bundlePath } },
102
+ plugins: [orcha],
103
+ };
104
+ ```
105
+
106
+ Next.js 16 uses Turbopack by default. Its config may be asynchronous, so the
107
+ integration compiles both browser and Node targets before returning the config
108
+ and also configures Webpack fallback builds:
109
+
110
+ ```ts
111
+ // next.config.ts
112
+ import { withOrcha } from "orchajs/next";
113
+
114
+ export default async function nextConfig() {
115
+ return withOrcha({});
116
+ }
117
+ ```
118
+
119
+ Both Expo and bare React Native use the same precompiled runtime and persistent
120
+ AsyncStorage:
121
+
122
+ ```bash
123
+ # Bare React Native
124
+ npm install @react-native-async-storage/async-storage
125
+
126
+ # Expo
127
+ npx expo install @react-native-async-storage/async-storage
128
+ ```
129
+
130
+ Bare React Native:
131
+
132
+ ```js
133
+ // metro.config.js
134
+ const { getDefaultConfig } = require("@react-native/metro-config");
135
+ const { withOrchaMetro } = require("orchajs/metro");
136
+
137
+ module.exports = withOrchaMetro(getDefaultConfig(__dirname));
138
+ ```
139
+
140
+ Expo:
141
+
142
+ ```js
143
+ // metro.config.js
144
+ const { getDefaultConfig } = require("expo/metro-config");
145
+ const { withOrchaExpo } = require("orchajs/expo");
146
+
147
+ module.exports = withOrchaExpo(getDefaultConfig(__dirname));
148
+ ```
149
+
150
+ Browser and React Native builds execute compiled agents locally. Only
151
+ Anthropic, DeepSeek, Google GenAI, and OpenAI are browser-compatible; Bedrock
152
+ and Vertex AI remain server runtimes. Provider credentials included in client
153
+ configuration are visible to end users, so production applications should use
154
+ restricted client credentials or a server-side provider proxy.
155
+
53
156
  ---
54
157
 
55
158
  ## The convention
package/dist/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/bin.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ void import("./cli.js").catch((error) => {
3
+ const message = error instanceof Error ? error.message : String(error);
4
+ const dependency = ["esbuild", "chokidar", "dotenv"].find((name) => message.includes(`"${name}"`) || message.includes(`'${name}'`));
5
+ if (dependency) {
6
+ console.error(`Orcha development tooling requires optional dependencies. Install them with:\n\n npm install --save-dev esbuild chokidar dotenv`);
7
+ }
8
+ else {
9
+ console.error(message);
10
+ }
11
+ process.exitCode = 1;
12
+ });
13
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare const orcha: import("./runtime-entry.js").OrchaClient;
2
+ export * from "./runtime-entry.js";
@@ -0,0 +1,12 @@
1
+ import { generateBrowserProviderResponse } from "./providers/browser.js";
2
+ import { setNativeRuntimeLoader } from "./runtime/actions/execute.js";
3
+ import { createOrcha } from "./runtime/create-orcha.js";
4
+ import { browserRuntimePlatform } from "./runtime/platform-browser.js";
5
+ setNativeRuntimeLoader(async () => {
6
+ const modulePath = "./runtime/actions/browser-native.js";
7
+ return import(modulePath);
8
+ });
9
+ export const orcha = createOrcha(() => {
10
+ throw new Error("The browser runtime requires a precompiled Orcha bundle. Configure the Orcha integration for your application bundler.");
11
+ }, generateBrowserProviderResponse, browserRuntimePlatform);
12
+ export * from "./runtime-entry.js";
package/dist/cli.js CHANGED
@@ -24,8 +24,7 @@ try {
24
24
  await initializeProject(projectRoot);
25
25
  break;
26
26
  case "dev":
27
- assertNoArguments(commandArguments, "dev");
28
- await watchProject(projectRoot);
27
+ await watchProject(projectRoot, parseDevTargets(commandArguments));
29
28
  break;
30
29
  case "run":
31
30
  await runAgent(projectRoot, commandArguments);
@@ -43,9 +42,13 @@ try {
43
42
  await exportSession(projectRoot, commandArguments);
44
43
  break;
45
44
  case "build": {
46
- assertNoArguments(commandArguments, "build");
45
+ const parsed = parseArguments(commandArguments, new Set(["--target"]), new Set());
46
+ if (parsed.positionals.length > 0) {
47
+ throw new Error("Usage: orcha build [--target node|browser|react-native]");
48
+ }
49
+ const target = parseBuildTarget(parsed.values.get("--target"));
47
50
  loadProjectEnvironment(projectRoot);
48
- const outputPath = await buildProject({ projectRoot });
51
+ const outputPath = await buildProject({ projectRoot, target });
49
52
  console.log(`Built ${relative(projectRoot, outputPath)}`);
50
53
  break;
51
54
  }
@@ -112,11 +115,12 @@ async function initializeProject(projectRoot) {
112
115
  await ensureGitignore(projectRoot);
113
116
  console.log('\nRun "orcha dev" to validate changes or "orcha run exampleAgent --input \\"Hello\\"" to execute the agent.');
114
117
  }
115
- async function watchProject(projectRoot) {
118
+ async function watchProject(projectRoot, targets) {
116
119
  const registryDirectory = resolve(projectRoot, "orcha");
117
120
  if (!existsSync(registryDirectory)) {
118
121
  throw new Error('Missing "orcha/". Run "orcha init" first.');
119
122
  }
123
+ loadProjectEnvironment(projectRoot);
120
124
  let validating = false;
121
125
  let validateAgain = false;
122
126
  let timer;
@@ -127,7 +131,9 @@ async function watchProject(projectRoot) {
127
131
  }
128
132
  validating = true;
129
133
  try {
130
- await loadProject(projectRoot);
134
+ for (const target of targets) {
135
+ await buildProject({ projectRoot, target });
136
+ }
131
137
  const agents = Object.keys(orcha.getCompiledBundle().agents);
132
138
  console.log(`[orcha] valid — ${agents.length} agent${agents.length === 1 ? "" : "s"}: ${agents.join(", ") || "none"}`);
133
139
  }
@@ -143,7 +149,7 @@ async function watchProject(projectRoot) {
143
149
  }
144
150
  };
145
151
  await validate();
146
- console.log("[orcha] watching orcha/**");
152
+ console.log(`[orcha] watching orcha/** for ${targets.join(", ")}`);
147
153
  const watcher = watch(registryDirectory, { ignoreInitial: true }).on("all", () => {
148
154
  clearTimeout(timer);
149
155
  timer = setTimeout(() => void validate(), 75);
@@ -344,6 +350,26 @@ function allAgentManifests(agents) {
344
350
  }
345
351
  return [...manifests.values()];
346
352
  }
353
+ function parseDevTargets(arguments_) {
354
+ const parsed = parseArguments(arguments_, new Set(["--target"]), new Set());
355
+ if (parsed.positionals.length > 0) {
356
+ throw new Error("Usage: orcha dev [--target node|browser|react-native|all]");
357
+ }
358
+ const target = parsed.values.get("--target") ?? "node";
359
+ if (target === "all") {
360
+ return ["browser", "react-native", "node"];
361
+ }
362
+ return [parseBuildTarget(target)];
363
+ }
364
+ function parseBuildTarget(value) {
365
+ if (value === undefined ||
366
+ value === "node" ||
367
+ value === "browser" ||
368
+ value === "react-native") {
369
+ return value ?? "node";
370
+ }
371
+ throw new Error(`Unknown build target "${value}". Expected node, browser, or react-native.`);
372
+ }
347
373
  function parseArguments(arguments_, valueOptions, flagOptions = new Set(["--json"])) {
348
374
  const parsed = {
349
375
  positionals: [],
@@ -605,13 +631,13 @@ function printUsage() {
605
631
  "",
606
632
  "Commands:",
607
633
  " init Add Orcha to the current project",
608
- " dev Validate and watch orcha/**",
634
+ " dev [--target <runtime>] Build and watch orcha/**",
609
635
  " run <agent> [options] Execute or resume an agent",
610
636
  " test [agent | agent/test] Run agent tests",
611
637
  " playground [options] Open the local agent playground",
612
638
  " migrate-storage --to <type> Copy sessions between JSONL and SQLite",
613
639
  " export-session <agent> <id> Export one session as JSONL",
614
- " build Build the production Orcha bundle",
640
+ " build [--target <runtime>] Build for node, browser, or react-native",
615
641
  "",
616
642
  "Run and test support --json for machine-readable output.",
617
643
  ].join("\n"));
@@ -1,4 +1,5 @@
1
1
  export interface BuildProjectOptions {
2
2
  projectRoot?: string;
3
+ target?: "node" | "browser" | "react-native";
3
4
  }
4
5
  export declare function buildProject(options?: BuildProjectOptions): Promise<string>;
@@ -4,9 +4,14 @@ import { dirname, resolve } from "node:path";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { build as bundleEntry } from "esbuild";
6
6
  import { orcha } from "../orcha.js";
7
+ import { setRegistryCompiler } from "../runtime/compiler-hook.js";
8
+ import { compileRegistry } from "./compile.js";
7
9
  import { builtInProviderCatalog, isBuiltInProvider, } from "../providers/catalog.js";
10
+ let registryImportSequence = 0;
8
11
  export async function buildProject(options = {}) {
9
12
  const projectRoot = resolve(options.projectRoot ?? process.cwd());
13
+ const target = options.target ?? "node";
14
+ setRegistryCompiler((configuration, compilerProjectRoot) => compileRegistry(configuration.agents, resolve(compilerProjectRoot, "orcha"), configuration.actions?.runtime ?? "native", target));
10
15
  const registryPath = resolve(projectRoot, "orcha/index.ts");
11
16
  if (!existsSync(registryPath)) {
12
17
  throw new Error('Missing "orcha/index.ts". Run "orcha init" first.');
@@ -14,7 +19,7 @@ export async function buildProject(options = {}) {
14
19
  const temporaryDirectory = resolve(projectRoot, ".orcha/.build");
15
20
  const registryBundlePath = resolve(temporaryDirectory, "registry.mjs");
16
21
  const productionEntryPath = resolve(temporaryDirectory, "production-entry.mjs");
17
- const outputPath = resolve(projectRoot, ".orcha/dist/bundle.js");
22
+ const outputPath = resolve(projectRoot, `.orcha/dist/${bundleFileName(target)}`);
18
23
  const manifestPath = resolve(projectRoot, ".orcha/dist/manifest.json");
19
24
  await mkdir(temporaryDirectory, { recursive: true });
20
25
  await mkdir(dirname(outputPath), { recursive: true });
@@ -34,7 +39,7 @@ export async function buildProject(options = {}) {
34
39
  process.env.ORCHA_COMPILING = "1";
35
40
  process.env.ORCHA_PROJECT_ROOT = projectRoot;
36
41
  try {
37
- await import(`${pathToFileURL(registryBundlePath).href}?time=${Date.now()}`);
42
+ await import(`${pathToFileURL(registryBundlePath).href}?build=${Date.now()}-${registryImportSequence++}`);
38
43
  }
39
44
  finally {
40
45
  if (previousCompiling === undefined) {
@@ -51,11 +56,19 @@ export async function buildProject(options = {}) {
51
56
  }
52
57
  }
53
58
  const compiledBundle = orcha.getCompiledBundle();
59
+ if (target !== "node" &&
60
+ compiledBundle.actionRuntime === "sandbox") {
61
+ throw new Error(`The ${target} target supports precompiled native actions only. Set actions.runtime to "native".`);
62
+ }
54
63
  const runtimeFactoryPath = resolve(dirname(fileURLToPath(import.meta.url)), "../runtime/create-orcha.js").replaceAll("\\", "/");
64
+ const runtimePlatformPath = resolve(dirname(fileURLToPath(import.meta.url)), `../runtime/platform-${target}.js`).replaceAll("\\", "/");
65
+ const runtimeEntryPath = resolve(dirname(fileURLToPath(import.meta.url)), "../runtime-entry.js").replaceAll("\\", "/");
55
66
  const providerDispatcherPath = resolve(dirname(fileURLToPath(import.meta.url)), "../providers/dispatcher.js").replaceAll("\\", "/");
56
67
  const sandboxRuntimeSource = compiledBundle.actionRuntime === "sandbox"
57
68
  ? createSandboxRuntimeSource()
58
69
  : "";
70
+ const platformActionRuntimeSource = createPlatformActionRuntimeSource(target);
71
+ const nodeStorageExports = target === "node" ? createNodeStorageExports() : "";
59
72
  const includedProviders = [
60
73
  ...new Set(allCompiledAgents(compiledBundle.agents).flatMap((agent) => [
61
74
  agent.provider,
@@ -64,18 +77,22 @@ export async function buildProject(options = {}) {
64
77
  .map((evaluation) => evaluation.provider),
65
78
  ])),
66
79
  ];
67
- const providerRuntimeSource = createProviderRuntimeSource(includedProviders);
80
+ const providerRuntimeSource = createProviderRuntimeSource(includedProviders, target);
68
81
  const needsNodeRequire = compiledBundle.actionRuntime === "sandbox" ||
69
82
  includedProviders.includes("vertexai") ||
70
83
  includedProviders.includes("bedrock");
71
84
  await writeFile(productionEntryPath, [
72
85
  `import { createOrcha } from ${JSON.stringify(runtimeFactoryPath)};`,
86
+ `import { ${runtimePlatformExport(target)} as runtimePlatform } from ${JSON.stringify(runtimePlatformPath)};`,
73
87
  `import { createProviderResponseGenerator } from ${JSON.stringify(providerDispatcherPath)};`,
88
+ `export * from ${JSON.stringify(runtimeEntryPath)};`,
89
+ nodeStorageExports,
74
90
  providerRuntimeSource,
91
+ platformActionRuntimeSource,
75
92
  sandboxRuntimeSource,
76
93
  `const compiledBundle = ${JSON.stringify(compiledBundle)};`,
77
94
  "const generateProviderResponse = createProviderResponseGenerator(includedProviders);",
78
- "export const orcha = createOrcha(() => compiledBundle, generateProviderResponse);",
95
+ "export const orcha = createOrcha(() => compiledBundle, generateProviderResponse, runtimePlatform);",
79
96
  "export default orcha;",
80
97
  "",
81
98
  ].join("\n"), "utf8");
@@ -84,14 +101,18 @@ export async function buildProject(options = {}) {
84
101
  outfile: outputPath,
85
102
  bundle: true,
86
103
  format: "esm",
87
- platform: "node",
88
- target: "node18",
104
+ platform: target === "node" ? "node" : "browser",
105
+ target: target === "node"
106
+ ? "node18"
107
+ : target === "browser"
108
+ ? ["chrome110", "firefox110", "safari16"]
109
+ : "es2022",
89
110
  minify: true,
90
111
  legalComments: "none",
91
112
  define: {
92
113
  "process.env.ORCHA_INCLUDE_SANDBOX": JSON.stringify(compiledBundle.actionRuntime === "sandbox" ? "1" : "0"),
93
114
  },
94
- ...(needsNodeRequire
115
+ ...(needsNodeRequire && target === "node"
95
116
  ? {
96
117
  banner: {
97
118
  js: [
@@ -101,6 +122,13 @@ export async function buildProject(options = {}) {
101
122
  },
102
123
  }
103
124
  : {}),
125
+ ...(target === "react-native"
126
+ ? {
127
+ external: [
128
+ "@react-native-async-storage/async-storage",
129
+ ],
130
+ }
131
+ : {}),
104
132
  logLevel: "silent",
105
133
  });
106
134
  await writeFile(manifestPath, `${JSON.stringify(compiledBundle)}\n`, "utf8");
@@ -113,6 +141,18 @@ export async function buildProject(options = {}) {
113
141
  });
114
142
  }
115
143
  }
144
+ function bundleFileName(target) {
145
+ return target === "node" ? "bundle.js" : `bundle.${target}.js`;
146
+ }
147
+ function runtimePlatformExport(target) {
148
+ if (target === "browser") {
149
+ return "browserRuntimePlatform";
150
+ }
151
+ if (target === "react-native") {
152
+ return "reactNativeRuntimePlatform";
153
+ }
154
+ return "nodeRuntimePlatform";
155
+ }
116
156
  function createSandboxRuntimeSource() {
117
157
  const runtimeDirectory = dirname(fileURLToPath(import.meta.url));
118
158
  const executePath = resolve(runtimeDirectory, "../runtime/actions/execute.js").replaceAll("\\", "/");
@@ -124,13 +164,36 @@ function createSandboxRuntimeSource() {
124
164
  "",
125
165
  ].join("\n");
126
166
  }
167
+ function createPlatformActionRuntimeSource(target) {
168
+ const runtimeDirectory = dirname(fileURLToPath(import.meta.url));
169
+ const executePath = resolve(runtimeDirectory, "../runtime/actions/execute.js").replaceAll("\\", "/");
170
+ const nativePath = resolve(runtimeDirectory, target === "node"
171
+ ? "../runtime/actions/native.js"
172
+ : "../runtime/actions/browser-native.js").replaceAll("\\", "/");
173
+ return [
174
+ `import { setNativeRuntimeLoader } from ${JSON.stringify(executePath)};`,
175
+ `import { executeNativeAction } from ${JSON.stringify(nativePath)};`,
176
+ "setNativeRuntimeLoader(async () => ({ executeNativeAction }));",
177
+ "",
178
+ ].join("\n");
179
+ }
180
+ function createNodeStorageExports() {
181
+ const sourceRoot = dirname(fileURLToPath(import.meta.url));
182
+ const jsonlPath = resolve(sourceRoot, "../storage/node-jsonl.js").replaceAll("\\", "/");
183
+ const sqlitePath = resolve(sourceRoot, "../storage/node-sqlite.js").replaceAll("\\", "/");
184
+ return [
185
+ `export { NodeJsonlSessionStore } from ${JSON.stringify(jsonlPath)};`,
186
+ `export { NodeSqliteSessionStore } from ${JSON.stringify(sqlitePath)};`,
187
+ "",
188
+ ].join("\n");
189
+ }
127
190
  function allCompiledAgents(agents) {
128
191
  return Object.values(agents).flatMap((agent) => [
129
192
  agent,
130
193
  ...Object.values(agent.subagents ?? {}),
131
194
  ]);
132
195
  }
133
- function createProviderRuntimeSource(providerNames) {
196
+ function createProviderRuntimeSource(providerNames, target) {
134
197
  const providersDirectory = resolve(dirname(fileURLToPath(import.meta.url)), "../providers");
135
198
  const imports = [];
136
199
  const entries = [];
@@ -138,6 +201,10 @@ function createProviderRuntimeSource(providerNames) {
138
201
  if (!isBuiltInProvider(name)) {
139
202
  throw new Error(`Provider "${name}" is not built in.`);
140
203
  }
204
+ if (target !== "node" &&
205
+ (name === "bedrock" || name === "vertexai")) {
206
+ throw new Error(`Provider "${name}" is not available for the ${target} target.`);
207
+ }
141
208
  const descriptor = builtInProviderCatalog[name];
142
209
  const localName = `provider${index}`;
143
210
  imports.push(`import { ${descriptor.exportName} as ${localName} } from ${JSON.stringify(resolve(providersDirectory, descriptor.moduleFile))};`);
@@ -1,3 +1,3 @@
1
1
  import type { AgentRegistration, CompiledBundle } from "../types.js";
2
- export declare function compileRegistry(registrations: Record<string, AgentRegistration>, registryRoot: string, actionRuntime?: "native" | "sandbox"): CompiledBundle;
2
+ export declare function compileRegistry(registrations: Record<string, AgentRegistration>, registryRoot: string, actionRuntime?: "native" | "sandbox", target?: "node" | "browser" | "react-native"): CompiledBundle;
3
3
  export declare function serializeBundle(bundle: CompiledBundle): string;
@@ -3,7 +3,7 @@ import { existsSync, readFileSync, readdirSync } from "node:fs";
3
3
  import { resolve } from "node:path";
4
4
  import { buildSync } from "esbuild";
5
5
  import { isBuiltInProvider } from "../providers/catalog.js";
6
- export function compileRegistry(registrations, registryRoot, actionRuntime = "native") {
6
+ export function compileRegistry(registrations, registryRoot, actionRuntime = "native", target = "node") {
7
7
  if (!registrations ||
8
8
  typeof registrations !== "object" ||
9
9
  Array.isArray(registrations)) {
@@ -20,9 +20,9 @@ export function compileRegistry(registrations, registryRoot, actionRuntime = "na
20
20
  if (!subagentKey.trim()) {
21
21
  throw new Error(`Agent "${key}" has an empty subagent name.`);
22
22
  }
23
- subagents[subagentKey] = compileAgent(subagentKey, registeredPath, registryRoot, actionRuntime);
23
+ subagents[subagentKey] = compileAgent(subagentKey, registeredPath, registryRoot, actionRuntime, target);
24
24
  }
25
- const parent = compileAgent(key, normalized.path, registryRoot, actionRuntime);
25
+ const parent = compileAgent(key, normalized.path, registryRoot, actionRuntime, target);
26
26
  agents[key] = Object.freeze({
27
27
  ...parent,
28
28
  subagentPolicy: Object.keys(subagents).length > 0
@@ -72,7 +72,7 @@ function normalizeAgentRegistration(key, registration) {
72
72
  subagents: registration.subagents ?? {},
73
73
  };
74
74
  }
75
- function compileAgent(key, registeredPath, registryRoot, actionRuntime) {
75
+ function compileAgent(key, registeredPath, registryRoot, actionRuntime, target) {
76
76
  const name = key;
77
77
  const sourceDirectory = resolve(registryRoot, registeredPath);
78
78
  const configPath = resolve(sourceDirectory, "index.json");
@@ -148,7 +148,7 @@ function compileAgent(key, registeredPath, registryRoot, actionRuntime) {
148
148
  reasoningLevel: configuration.reasoningLevel,
149
149
  outputType: configuration.outputType ?? "text",
150
150
  outputSchema: configuration.outputSchema,
151
- actions: compileActions(name, sourceDirectory, actionRuntime),
151
+ actions: compileActions(name, sourceDirectory, actionRuntime, target),
152
152
  skills: compileSkills(name, sourceDirectory),
153
153
  evaluations: compileEvaluations(name, sourceDirectory),
154
154
  subagentPolicy: configuration.subagents
@@ -157,7 +157,7 @@ function compileAgent(key, registeredPath, registryRoot, actionRuntime) {
157
157
  subagents: Object.freeze({}),
158
158
  });
159
159
  }
160
- function compileActions(agentName, sourceDirectory, actionRuntime) {
160
+ function compileActions(agentName, sourceDirectory, actionRuntime, target) {
161
161
  const actionsDirectory = resolve(sourceDirectory, "actions");
162
162
  if (!existsSync(actionsDirectory)) {
163
163
  return {};
@@ -229,7 +229,7 @@ function compileActions(agentName, sourceDirectory, actionRuntime) {
229
229
  throw new Error(`Agent "${agentName}" has duplicate action name "${configuration.name}".`);
230
230
  }
231
231
  const compiledSource = execution === "local"
232
- ? compileLocalAction(agentName, entry.name, actionsDirectory, actionRuntime)
232
+ ? compileLocalAction(agentName, entry.name, actionsDirectory, actionRuntime, target)
233
233
  : undefined;
234
234
  actions[configuration.name] = Object.freeze({
235
235
  ...configuration,
@@ -413,7 +413,7 @@ function validateEvaluationConfiguration(agentName, registrationName, configurat
413
413
  names.add(metric.name);
414
414
  }
415
415
  }
416
- function compileLocalAction(agentName, directoryName, actionsDirectory, actionRuntime) {
416
+ function compileLocalAction(agentName, directoryName, actionsDirectory, actionRuntime, target) {
417
417
  const entryPath = resolve(actionsDirectory, directoryName, "index.js");
418
418
  if (!existsSync(entryPath)) {
419
419
  throw new Error(`Local action "${agentName}/${directoryName}" requires index.js.`);
@@ -426,7 +426,9 @@ function compileLocalAction(agentName, directoryName, actionsDirectory, actionRu
426
426
  write: false,
427
427
  format: "iife",
428
428
  globalName: "__orchaActionModule",
429
- platform: actionRuntime === "native" ? "node" : "neutral",
429
+ platform: actionRuntime === "native" && target === "node"
430
+ ? "node"
431
+ : "browser",
430
432
  target: "es2022",
431
433
  logLevel: "silent",
432
434
  });
@@ -1,5 +1,3 @@
1
- import { readFile } from "node:fs/promises";
2
- import { basename, extname, resolve } from "node:path";
3
1
  const MIME_TYPES = {
4
2
  ".csv": "text/csv",
5
3
  ".doc": "application/msword",
@@ -21,8 +19,8 @@ const MIME_TYPES = {
21
19
  ".xls": "application/vnd.ms-excel",
22
20
  ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
23
21
  };
24
- export function normalizeLocalFile(filePath, mimeType, projectRoot = process.cwd()) {
25
- const absolutePath = resolve(projectRoot, filePath);
22
+ export function normalizeLocalFile(filePath, mimeType, projectRoot = ".") {
23
+ const absolutePath = resolvePortablePath(projectRoot, filePath);
26
24
  return {
27
25
  type: "file",
28
26
  filePath: absolutePath,
@@ -47,22 +45,60 @@ export function normalizeUrlContent(url, mimeType) {
47
45
  };
48
46
  }
49
47
  export async function readLocalFileContent(content) {
48
+ const fsModule = "node:fs/promises";
49
+ const { readFile } = await import(fsModule);
50
50
  const bytes = await readFile(content.filePath);
51
51
  const base64 = bytes.toString("base64");
52
52
  return {
53
53
  bytes,
54
54
  base64,
55
55
  dataUri: `data:${content.mimeType};base64,${base64}`,
56
- fileName: basename(content.filePath),
56
+ fileName: portableBasename(content.filePath),
57
57
  };
58
58
  }
59
59
  function normalizeMimeType(mimeType, source) {
60
60
  if (mimeType?.trim()) {
61
61
  return mimeType.trim().toLowerCase();
62
62
  }
63
- const inferred = MIME_TYPES[extname(source).toLowerCase()];
63
+ const inferred = MIME_TYPES[portableExtension(source).toLowerCase()];
64
64
  if (!inferred) {
65
65
  throw new Error(`Could not infer a MIME type for "${source}". Provide mimeType explicitly.`);
66
66
  }
67
67
  return inferred;
68
68
  }
69
+ function resolvePortablePath(root, filePath) {
70
+ if (/^(?:\/|[a-zA-Z]:[\\/])/.test(filePath)) {
71
+ return normalizePath(filePath);
72
+ }
73
+ return normalizePath(`${root.replace(/[\\/]+$/, "")}/${filePath}`);
74
+ }
75
+ function normalizePath(path) {
76
+ const separator = path.includes("\\") ? "\\" : "/";
77
+ const prefix = path.match(/^(?:[a-zA-Z]:)?[\\/]/)?.[0] ?? "";
78
+ const source = prefix ? path.slice(prefix.length) : path;
79
+ const parts = [];
80
+ for (const part of source.split(/[\\/]+/)) {
81
+ if (!part || part === ".") {
82
+ continue;
83
+ }
84
+ if (part === "..") {
85
+ if (parts.length > 0 && parts.at(-1) !== "..") {
86
+ parts.pop();
87
+ }
88
+ else if (!prefix) {
89
+ parts.push(part);
90
+ }
91
+ continue;
92
+ }
93
+ parts.push(part);
94
+ }
95
+ return `${prefix}${parts.join(separator)}` || ".";
96
+ }
97
+ function portableBasename(path) {
98
+ return path.split(/[\\/]/).at(-1) ?? path;
99
+ }
100
+ function portableExtension(path) {
101
+ const name = portableBasename(path);
102
+ const index = name.lastIndexOf(".");
103
+ return index > 0 ? name.slice(index) : "";
104
+ }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,4 @@
1
1
  export { orcha } from "./orcha.js";
2
- export { OrchaError } from "./errors.js";
3
- export type { Orcha, OrchaClient } from "./orcha.js";
2
+ export * from "./runtime-entry.js";
4
3
  export { NodeJsonlSessionStore } from "./storage/node-jsonl.js";
5
4
  export { NodeSqliteSessionStore } from "./storage/node-sqlite.js";
6
- export { exportSessionJsonl, migrateSessionStore, } from "./storage/migrate.js";
7
- export type { SessionStoreMigrationResult, } from "./storage/migrate.js";
8
- export type { ActionConfiguration, AgentTestActionConfiguration, AgentTestActionExpectation, AgentTestActionResponse, AgentTestAssertionResult, AgentTestCaseConfiguration, AgentTestCaseReport, AgentTestCaseSummary, AgentTestExpectation, AgentTestReport, AgentTestTextExpectation, AgentTestValueExpectation, AgentTestWarning, ApiKeyProviderConfiguration, AwsCredentials, AgentContinueInput, AgentConfiguration, AgentContentInput, AgentInput, AgentRegistration, AgentRuntime, ClientCapability, ClientToolCall, CompletedRunResult, CompiledActionManifest, CompiledAgentManifest, CompiledBundle, CompiledEvaluationManifest, CompiledSkillManifest, EvaluationConfiguration, EvaluationMetricConfiguration, EvaluationMetricResult, EvaluationResult, Execution, ExecutionSnapshot, FailedRunResult, FileContent, FilePathContentInput, LocalFileContent, LocalActionRuntimeConfiguration, MessageContent, MessageContentInput, MetadataValue, OrchaErrorCode, OrchaInitConfiguration, PausedRunResult, PaginationOptions, ProjectConfiguration, ProviderConfiguration, ProviderInitConfigurations, ProviderName, BedrockProviderConfiguration, RunError, RunStatus, RunTestsOptions, ResumeInput, RunResult, SessionEvent, SessionEventListOptions, SessionEvents, SessionEventType, SessionHistory, SessionHistoryItem, SessionList, SessionListOptions, SessionMetadata, SessionSnapshot, SessionStatus, SessionStore, SkillConfiguration, SessionUpdate, StreamingRunSnapshot, SubagentConfiguration, TextContent, ToolResult, ToolResumeInput, UrlContentInput, Usage, VertexAIProviderConfiguration, GoogleServiceAccountCredentials, WaitingRunResult, WaitingForSubagentSnapshot, } from "./types.js";
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export { orcha } from "./orcha.js";
2
- export { OrchaError } from "./errors.js";
2
+ export * from "./runtime-entry.js";
3
3
  export { NodeJsonlSessionStore } from "./storage/node-jsonl.js";
4
4
  export { NodeSqliteSessionStore } from "./storage/node-sqlite.js";
5
- export { exportSessionJsonl, migrateSessionStore, } from "./storage/migrate.js";
@@ -6,12 +6,15 @@ import { buildProject } from "../compiler/build-project.js";
6
6
  */
7
7
  export function orchaPlugin(options = {}) {
8
8
  const projectRoot = resolve(options.projectRoot ?? process.cwd());
9
- const generatedBundle = resolve(projectRoot, ".orcha/dist/bundle.js");
10
9
  return {
11
10
  name: "orchajs",
12
11
  setup(builder) {
12
+ const target = builder.initialOptions.platform === "browser"
13
+ ? "browser"
14
+ : "node";
15
+ const generatedBundle = resolve(projectRoot, `.orcha/dist/${target === "node" ? "bundle.js" : "bundle.browser.js"}`);
13
16
  builder.onStart(async () => {
14
- await buildProject({ projectRoot });
17
+ await buildProject({ projectRoot, target });
15
18
  });
16
19
  builder.onResolve({ filter: /^orchajs$/ }, () => ({
17
20
  path: generatedBundle,
@@ -0,0 +1 @@
1
+ export { withOrchaMetro as withOrchaExpo, type OrchaMetroOptions as OrchaExpoOptions, } from "./metro.js";
@@ -0,0 +1 @@
1
+ export { withOrchaMetro as withOrchaExpo, } from "./metro.js";
@@ -0,0 +1,15 @@
1
+ export interface OrchaMetroOptions {
2
+ projectRoot?: string;
3
+ }
4
+ interface MetroResolverContext {
5
+ resolveRequest(context: MetroResolverContext, moduleName: string, platform: string | null): unknown;
6
+ }
7
+ interface MetroConfiguration {
8
+ resolver?: {
9
+ resolveRequest?: MetroResolverContext["resolveRequest"];
10
+ [key: string]: unknown;
11
+ };
12
+ [key: string]: unknown;
13
+ }
14
+ export declare function withOrchaMetro<T extends MetroConfiguration>(configuration: T, options?: OrchaMetroOptions): Promise<T>;
15
+ export {};