orchajs 0.6.2 → 0.7.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.
- package/README.md +32 -7
- package/dist/cli-agents-template.d.ts +1 -1
- package/dist/cli-agents-template.d.ts.map +1 -1
- package/dist/cli-agents-template.js +15 -5
- package/dist/cli-agents-template.js.map +1 -1
- package/dist/file-content.d.ts +14 -0
- package/dist/file-content.d.ts.map +1 -0
- package/dist/file-content.js +69 -0
- package/dist/file-content.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +30 -6
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/bedrock.d.ts.map +1 -1
- package/dist/providers/bedrock.js +70 -7
- package/dist/providers/bedrock.js.map +1 -1
- package/dist/providers/google-gemini.d.ts.map +1 -1
- package/dist/providers/google-gemini.js +28 -4
- package/dist/providers/google-gemini.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +20 -4
- package/dist/providers/openai.js.map +1 -1
- package/dist/runtime/agent.d.ts +1 -0
- package/dist/runtime/agent.d.ts.map +1 -1
- package/dist/runtime/agent.js +127 -11
- package/dist/runtime/agent.js.map +1 -1
- package/dist/runtime/create-orcha.d.ts.map +1 -1
- package/dist/runtime/create-orcha.js +2 -0
- package/dist/runtime/create-orcha.js.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -0
- package/dist/testing.js.map +1 -1
- package/dist/types.d.ts +21 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/runtime/agent.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { OrchaError } from "../errors.js";
|
|
3
|
+
import { normalizeLocalFile, normalizeUrlContent, } from "../file-content.js";
|
|
3
4
|
import { messagesFromEvents, normalizePersistedToolResults, SessionEventWriter, } from "./session-events.js";
|
|
4
5
|
import { validateStructuredValue } from "./structured-output.js";
|
|
5
6
|
import { executeLocalAction } from "./actions/execute.js";
|
|
@@ -25,6 +26,7 @@ export class RuntimeAgent {
|
|
|
25
26
|
#delegatedOnly;
|
|
26
27
|
#agentKey;
|
|
27
28
|
#sessionIdPrefix;
|
|
29
|
+
#projectRoot;
|
|
28
30
|
#evaluationTasks = new Map();
|
|
29
31
|
#sessionIdleWaiters = new Map();
|
|
30
32
|
constructor(options) {
|
|
@@ -38,6 +40,7 @@ export class RuntimeAgent {
|
|
|
38
40
|
this.#delegatedOnly = options.delegatedOnly ?? false;
|
|
39
41
|
this.#agentKey = options.manifest.key ?? options.manifest.name;
|
|
40
42
|
this.#sessionIdPrefix = options.sessionIdPrefix ?? "ses_";
|
|
43
|
+
this.#projectRoot = options.projectRoot ?? process.cwd();
|
|
41
44
|
}
|
|
42
45
|
get agent() {
|
|
43
46
|
return this.#agentKey;
|
|
@@ -379,7 +382,13 @@ export class RuntimeAgent {
|
|
|
379
382
|
return [...events, ...recoveryEvents];
|
|
380
383
|
}
|
|
381
384
|
async #start(sessionId, input, createSession = true, publishOutput, publishSnapshot, lineage) {
|
|
382
|
-
|
|
385
|
+
let content;
|
|
386
|
+
try {
|
|
387
|
+
content = normalizeContent(input.content, this.#projectRoot);
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
return failure(sessionId, "invalid_input", error instanceof Error ? error.message : String(error));
|
|
391
|
+
}
|
|
383
392
|
if (!content) {
|
|
384
393
|
return failure(sessionId, "invalid_input", "Agent content must contain at least one valid item.");
|
|
385
394
|
}
|
|
@@ -1040,8 +1049,8 @@ export class RuntimeAgent {
|
|
|
1040
1049
|
description: "The registered subagent to run.",
|
|
1041
1050
|
},
|
|
1042
1051
|
input: {
|
|
1043
|
-
|
|
1044
|
-
description: "The complete
|
|
1052
|
+
...agentContentInputSchema(),
|
|
1053
|
+
description: "The complete text or multimodal content for the subagent. Local file paths resolve from the configured Orcha project root.",
|
|
1045
1054
|
},
|
|
1046
1055
|
},
|
|
1047
1056
|
required: ["agent", "input"],
|
|
@@ -1123,15 +1132,16 @@ export class RuntimeAgent {
|
|
|
1123
1132
|
async #executeSubagentToolCall(parentSessionId, writer, call, events, publishSnapshot) {
|
|
1124
1133
|
if (call.name === RUN_AGENT_TOOL_NAME) {
|
|
1125
1134
|
const agentName = requiredToolString(call.arguments.agent, "agent");
|
|
1126
|
-
const input = requiredToolString(call.arguments.input, "input");
|
|
1127
1135
|
const child = this.#subagents[agentName];
|
|
1128
1136
|
if (!child) {
|
|
1129
1137
|
throw new Error(`Unknown subagent "${agentName}".`);
|
|
1130
1138
|
}
|
|
1131
|
-
const
|
|
1139
|
+
const parentEvents = await this.#readSession(parentSessionId);
|
|
1140
|
+
const existing = previousSubagentCall(parentEvents, call.callId);
|
|
1132
1141
|
if (existing) {
|
|
1133
1142
|
return subagentToolOutput(existing);
|
|
1134
1143
|
}
|
|
1144
|
+
const input = normalizeDelegatedInput(call.arguments.input, this.#projectRoot);
|
|
1135
1145
|
const lineage = {
|
|
1136
1146
|
origin: "delegated",
|
|
1137
1147
|
parentAgent: this.#manifest.key,
|
|
@@ -1147,7 +1157,7 @@ export class RuntimeAgent {
|
|
|
1147
1157
|
});
|
|
1148
1158
|
await this.#store.append(parentSessionId, [initiated]);
|
|
1149
1159
|
events.push(initiated);
|
|
1150
|
-
const childExecution = child.runAsChild(childSessionId, input, lineage);
|
|
1160
|
+
const childExecution = child.runAsChild(childSessionId, { content: input }, lineage);
|
|
1151
1161
|
publishSnapshot?.({
|
|
1152
1162
|
sessionId: parentSessionId,
|
|
1153
1163
|
status: "waiting_for_subagent",
|
|
@@ -1621,24 +1631,49 @@ function isEvaluationMetricResult(value) {
|
|
|
1621
1631
|
Array.isArray(value.evidence) &&
|
|
1622
1632
|
value.evidence.every((item) => typeof item === "string"));
|
|
1623
1633
|
}
|
|
1624
|
-
function normalizeContent(content) {
|
|
1634
|
+
function normalizeContent(content, projectRoot) {
|
|
1625
1635
|
if (typeof content === "string") {
|
|
1626
1636
|
return content.trim()
|
|
1627
1637
|
? [{ type: "text", text: content }]
|
|
1628
1638
|
: undefined;
|
|
1629
1639
|
}
|
|
1630
|
-
|
|
1640
|
+
const items = Array.isArray(content)
|
|
1641
|
+
? content
|
|
1642
|
+
: [content];
|
|
1643
|
+
if (items.length === 0) {
|
|
1631
1644
|
return undefined;
|
|
1632
1645
|
}
|
|
1633
1646
|
const normalized = [];
|
|
1634
|
-
for (const item of
|
|
1635
|
-
if (item
|
|
1647
|
+
for (const item of items) {
|
|
1648
|
+
if (item &&
|
|
1649
|
+
"type" in item &&
|
|
1650
|
+
item.type === "text" &&
|
|
1636
1651
|
typeof item.text === "string" &&
|
|
1637
1652
|
item.text.trim()) {
|
|
1638
1653
|
normalized.push({ type: "text", text: item.text });
|
|
1639
1654
|
continue;
|
|
1640
1655
|
}
|
|
1641
1656
|
if (item &&
|
|
1657
|
+
"filePath" in item &&
|
|
1658
|
+
typeof item.filePath === "string" &&
|
|
1659
|
+
item.filePath.trim()) {
|
|
1660
|
+
normalized.push(normalizeLocalFile(item.filePath, "mimeType" in item && typeof item.mimeType === "string"
|
|
1661
|
+
? item.mimeType
|
|
1662
|
+
: undefined, projectRoot));
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1665
|
+
if (item &&
|
|
1666
|
+
"url" in item &&
|
|
1667
|
+
typeof item.url === "string" &&
|
|
1668
|
+
item.url.trim()) {
|
|
1669
|
+
normalized.push(normalizeUrlContent(item.url, "mimeType" in item && typeof item.mimeType === "string"
|
|
1670
|
+
? item.mimeType
|
|
1671
|
+
: undefined));
|
|
1672
|
+
continue;
|
|
1673
|
+
}
|
|
1674
|
+
if (item &&
|
|
1675
|
+
"type" in item &&
|
|
1676
|
+
typeof item.type === "string" &&
|
|
1642
1677
|
["image", "video", "audio", "url"].includes(item.type) &&
|
|
1643
1678
|
"mimeType" in item &&
|
|
1644
1679
|
"fileUri" in item &&
|
|
@@ -1653,6 +1688,82 @@ function normalizeContent(content) {
|
|
|
1653
1688
|
}
|
|
1654
1689
|
return normalized;
|
|
1655
1690
|
}
|
|
1691
|
+
function normalizeDelegatedInput(input, projectRoot) {
|
|
1692
|
+
if (typeof input === "string") {
|
|
1693
|
+
if (!input.trim()) {
|
|
1694
|
+
throw new Error('run_agent requires a non-empty "input".');
|
|
1695
|
+
}
|
|
1696
|
+
return input;
|
|
1697
|
+
}
|
|
1698
|
+
if (!isRecord(input) && !Array.isArray(input)) {
|
|
1699
|
+
throw new Error("run_agent input must be text, one content item, or a content array.");
|
|
1700
|
+
}
|
|
1701
|
+
const content = normalizeContent(input, projectRoot);
|
|
1702
|
+
if (!content) {
|
|
1703
|
+
throw new Error("run_agent input must contain at least one valid content item.");
|
|
1704
|
+
}
|
|
1705
|
+
return content;
|
|
1706
|
+
}
|
|
1707
|
+
function agentContentInputSchema() {
|
|
1708
|
+
const textItem = {
|
|
1709
|
+
type: "object",
|
|
1710
|
+
properties: {
|
|
1711
|
+
type: { type: "string", enum: ["text"] },
|
|
1712
|
+
text: { type: "string", minLength: 1 },
|
|
1713
|
+
},
|
|
1714
|
+
required: ["type", "text"],
|
|
1715
|
+
additionalProperties: false,
|
|
1716
|
+
};
|
|
1717
|
+
const fileItems = [
|
|
1718
|
+
{
|
|
1719
|
+
type: "object",
|
|
1720
|
+
properties: {
|
|
1721
|
+
type: { type: "string", enum: ["file"] },
|
|
1722
|
+
filePath: { type: "string", minLength: 1 },
|
|
1723
|
+
mimeType: { type: "string", minLength: 1 },
|
|
1724
|
+
},
|
|
1725
|
+
required: ["filePath"],
|
|
1726
|
+
additionalProperties: false,
|
|
1727
|
+
},
|
|
1728
|
+
{
|
|
1729
|
+
type: "object",
|
|
1730
|
+
properties: {
|
|
1731
|
+
type: { type: "string", enum: ["url"] },
|
|
1732
|
+
url: { type: "string", minLength: 1 },
|
|
1733
|
+
mimeType: { type: "string", minLength: 1 },
|
|
1734
|
+
},
|
|
1735
|
+
required: ["url"],
|
|
1736
|
+
additionalProperties: false,
|
|
1737
|
+
},
|
|
1738
|
+
{
|
|
1739
|
+
type: "object",
|
|
1740
|
+
properties: {
|
|
1741
|
+
type: {
|
|
1742
|
+
type: "string",
|
|
1743
|
+
enum: ["image", "video", "audio", "url"],
|
|
1744
|
+
},
|
|
1745
|
+
fileUri: { type: "string", minLength: 1 },
|
|
1746
|
+
mimeType: { type: "string", minLength: 1 },
|
|
1747
|
+
},
|
|
1748
|
+
required: ["type", "fileUri", "mimeType"],
|
|
1749
|
+
additionalProperties: false,
|
|
1750
|
+
},
|
|
1751
|
+
];
|
|
1752
|
+
const item = {
|
|
1753
|
+
anyOf: [textItem, ...fileItems],
|
|
1754
|
+
};
|
|
1755
|
+
return {
|
|
1756
|
+
anyOf: [
|
|
1757
|
+
{ type: "string", minLength: 1 },
|
|
1758
|
+
item,
|
|
1759
|
+
{
|
|
1760
|
+
type: "array",
|
|
1761
|
+
items: item,
|
|
1762
|
+
minItems: 1,
|
|
1763
|
+
},
|
|
1764
|
+
],
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1656
1767
|
function normalizeClientCapabilities(capabilities) {
|
|
1657
1768
|
const names = [];
|
|
1658
1769
|
for (const capability of capabilities) {
|
|
@@ -1750,7 +1861,8 @@ function buildSystemPrompt(manifest, events, variables) {
|
|
|
1750
1861
|
if (subagents.length > 0) {
|
|
1751
1862
|
sections.push([
|
|
1752
1863
|
"## Available subagents",
|
|
1753
|
-
"Use `run_agent` to start a specialist. Give it the complete task and only the context it needs.",
|
|
1864
|
+
"Use `run_agent` to start a specialist. Give it the complete task and only the context it needs. Its input accepts the same text and multimodal content format as a normal agent run.",
|
|
1865
|
+
"Local file paths in subagent input resolve from the configured Orcha project root.",
|
|
1754
1866
|
"You may request multiple independent subagents in one response; Orcha runs them concurrently and returns each result by call ID.",
|
|
1755
1867
|
"The call waits synchronously while the child is actively running, and the child's text response returns as a normal tool result.",
|
|
1756
1868
|
"If a child pauses for a client action or because its session was paused, decide whether to resume it with `resume_agent`, inspect it with `inspect_agent`, invoke one of your own client actions for missing information, or continue without it.",
|
|
@@ -2281,6 +2393,10 @@ function isMessageContent(value) {
|
|
|
2281
2393
|
if (value.type === "text") {
|
|
2282
2394
|
return typeof value.text === "string";
|
|
2283
2395
|
}
|
|
2396
|
+
if (value.type === "file") {
|
|
2397
|
+
return (typeof value.mimeType === "string" &&
|
|
2398
|
+
typeof value.filePath === "string");
|
|
2399
|
+
}
|
|
2284
2400
|
return (["image", "video", "audio", "url"].includes(value.type) &&
|
|
2285
2401
|
typeof value.mimeType === "string" &&
|
|
2286
2402
|
typeof value.fileUri === "string");
|