Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/calm-skills-compose.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eve": patch
---

Compile the default `load_skill` tool as an ordinary agent source. The tool now reads the active node's skills from runtime context, so application overrides use the same path-based composition rules without a framework-only closure factory.
5 changes: 5 additions & 0 deletions .changeset/fresh-connection-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eve": patch
---

Compile `connection_search` as an ordinary dynamic tool source and keep discovered connection tools exclusively in durable context. Existing sessions without that context search again instead of reconstructing tools from message history.
5 changes: 5 additions & 0 deletions .changeset/light-web-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eve": patch
---

Compose the default Exa-backed `web_search` configuration from the canonical `tools/web_search.ts` source slot, so application provider configuration and custom tool replacements override it through the ordinary source graph.
5 changes: 5 additions & 0 deletions .changeset/true-framework-channels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eve": patch
---

Compile the default eve channel and six runtime callback routes from root-only canonical channel sources. Application channel definitions and disable sentinels can now replace each framework route through ordinary path-based composition.
5 changes: 5 additions & 0 deletions .changeset/warm-framework-sources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eve": patch
---

Compile the default sandbox and core workspace tools through the same module-source pipeline as application-authored definitions. Application files continue to override defaults by their path-derived identity.
12 changes: 3 additions & 9 deletions packages/eve/src/cli/dev/tui/tool-presentation.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { describe, expect, it } from "vitest";

import { getAllFrameworkToolNames } from "#runtime/framework-tools/index.js";

import { presentPreparingTool, presentTool } from "./tool-presentation.js";

describe("presentPreparingTool", () => {
Expand Down Expand Up @@ -169,11 +167,12 @@ describe("presentTool", () => {
expect(presentTool("final_output", { anything: true }).title).toBe("Return final output");
});

it("covers every framework builtin with semantic copy", () => {
it("covers every native and default tool with semantic copy", () => {
const representativeInputs: Record<string, unknown> = {
agent: { message: "audit the auth flow" },
ask_question: { prompt: "Which environment?" },
bash: { command: "ls" },
connection_search: { keywords: "linear issues" },
glob: { pattern: "**/*.ts" },
grep: { pattern: "useEve" },
load_skill: { skill: "commit" },
Expand All @@ -186,12 +185,7 @@ describe("presentTool", () => {
write_file: { filePath: "/workspace/a.ts", content: "x" },
};

for (const name of getAllFrameworkToolNames()) {
const input = representativeInputs[name];
expect(
input,
`framework tool "${name}" has no representative input — add semantic copy for it in tool-presentation.ts and cover it here`,
).toBeDefined();
for (const [name, input] of Object.entries(representativeInputs)) {
expect(presentTool(name, input).title, name).not.toBe(name);
}
});
Expand Down
1 change: 1 addition & 0 deletions packages/eve/src/compiler/agent-module-candidate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type AgentSourceLayer =

export interface AgentModuleCandidate {
readonly backing: CompiledModuleBacking;
readonly extensionNamespace?: string;
readonly layer: AgentSourceLayer;
readonly logicalPath: string;
readonly nodeId: string;
Expand Down
11 changes: 11 additions & 0 deletions packages/eve/src/compiler/compile-from-memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ROOT_COMPILED_AGENT_NODE_ID,
} from "#compiler/manifest.js";
import type { CompiledModuleMap } from "#compiler/module-map.js";
import { prepareKernelCapabilities } from "#compiler/prepare-kernel-capabilities.js";

/**
* Declarative description of an in-memory authored agent used by the test
Expand Down Expand Up @@ -131,6 +132,16 @@ export function compileFromMemory(input: CompileFromMemoryInput): CompileFromMem
agentRoot,
appRoot,
config,
kernelCapabilities: prepareKernelCapabilities({
disabled: new Set(),
frameworkLoadSkill: true,
hasSkills: skills.length > 0,
isRoot: true,
tasksEnabled: true,
toolNames: new Set(tools.map((tool) => tool.name)),
webSearch: false,
workflow: false,
}),
skills,
tools,
});
Expand Down
218 changes: 218 additions & 0 deletions packages/eve/src/compiler/compose-agent-sources.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
import { describe, expect, it } from "vitest";

import { composeAgentSources, getSubagentSourceOrigin } from "#compiler/compose-agent-sources.js";
import {
createAgentSourceManifest,
createConnectionSourceRef,
createLocalSubagentSourceRef,
createModuleSourceRef,
} from "#discover/manifest.js";
import { frameworkAgentSourceRegistry } from "#framework-sources/registry.js";

describe("composeAgentSources", () => {
it("uses application channels, tools, and sandbox modules for matching canonical slots", () => {
const result = composeAgentSources({
isRoot: true,
manifest: createAgentSourceManifest({
agentId: "root",
agentRoot: "/app/agent",
appRoot: "/app",
channels: [createModuleSourceRef({ logicalPath: "channels/eve.ts" })],
sandbox: createModuleSourceRef({ logicalPath: "sandbox/sandbox.ts" }),
tools: [createModuleSourceRef({ logicalPath: "tools/bash.ts" })],
}),
nodeId: "root",
registry: frameworkAgentSourceRegistry,
});

expect(
result.manifest.tools.find((tool) => tool.logicalPath === "tools/bash.ts")?.sourceId,
).toBe("tools/bash.ts");
expect(result.manifest.sandbox?.sourceId).toBe("sandbox/sandbox.ts");
expect(
result.manifest.channels.find((channel) => channel.logicalPath === "channels/eve.ts")
?.sourceId,
).toBe("channels/eve.ts");
expect(result.bindings["eve.framework-root:channels/eve.ts"]).toBeUndefined();
expect(result.bindings["eve.framework-defaults:tools/bash.ts"]).toBeUndefined();
expect(result.bindings["eve.framework-defaults:sandbox.ts"]).toBeUndefined();
});

it("binds non-overridden defaults to their programmatic owners", () => {
const result = composeAgentSources({
isRoot: false,
manifest: createAgentSourceManifest({
agentId: "child",
agentRoot: "/app/agent/subagents/child",
appRoot: "/app",
}),
nodeId: "subagents/child",
registry: frameworkAgentSourceRegistry,
});

expect(result.manifest.tools.map((tool) => tool.logicalPath)).toEqual([
"tools/bash.ts",
"tools/connection_search.ts",
"tools/load_skill.ts",
"tools/read_file.ts",
"tools/todo.ts",
"tools/web_fetch.ts",
"tools/web_search.ts",
"tools/write_file.ts",
]);
expect(result.manifest.channels).toEqual([]);
expect(result.manifest.sandbox?.logicalPath).toBe("sandbox.ts");
expect(result.bindings["eve.framework-defaults:tools/bash.ts"]).toEqual({
backing: {
kind: "programmatic",
moduleId: "tools/bash.ts",
registryId: "eve.framework-defaults",
},
logicalPath: "tools/bash.ts",
owner: { feature: "eve.framework-defaults", kind: "framework" },
});
});

it("projects every extension primitive before selecting override and application winners", () => {
const extensionRoot = "/packages/crm/extension";
const overrideRoot = "/app/agent/extensions/crm";
const extensionManifest = createAgentSourceManifest({
agentRoot: extensionRoot,
appRoot: "/packages/crm",
channels: [createModuleSourceRef({ logicalPath: "channels/webhooks/events.ts" })],
connections: [
createConnectionSourceRef({ connectionName: "api", logicalPath: "connections/api.ts" }),
],
hooks: [createModuleSourceRef({ logicalPath: "hooks/session/start.ts" })],
instructions: [
{
definition: { content: "CRM instructions", role: "system" },
logicalPath: "instructions.md",
sourceId: "instructions.md",
sourceKind: "markdown",
},
],
schedules: [createModuleSourceRef({ logicalPath: "schedules/daily/sync.ts" })],
skills: [createModuleSourceRef({ logicalPath: "skills/research.ts" })],
tools: [
createModuleSourceRef({ logicalPath: "tools/search.ts" }),
createModuleSourceRef({ logicalPath: "tools/list.ts" }),
],
});
const overrides = createAgentSourceManifest({
agentRoot: overrideRoot,
appRoot: "/app",
tools: [createModuleSourceRef({ logicalPath: "tools/search.ts" })],
});
const result = composeAgentSources({
isRoot: true,
manifest: createAgentSourceManifest({
agentRoot: "/app/agent",
appRoot: "/app",
resolvedExtensions: [
{
externalDependencies: ["@acme/sdk"],
manifest: extensionManifest,
namespace: "crm",
overrides,
packageName: "@acme/crm",
packageRoot: "/packages/crm",
sourceRoot: extensionRoot,
specifier: "@acme/crm",
},
],
tools: [createModuleSourceRef({ logicalPath: "tools/crm__list.ts" })],
}),
nodeId: "root",
registry: frameworkAgentSourceRegistry,
});

expect(result.manifest.channels.map((source) => source.logicalPath)).toContain(
"channels/crm__webhooks/events.ts",
);
expect(result.manifest.connections).toEqual([
expect.objectContaining({
connectionName: "crm__api",
logicalPath: "connections/crm__api.ts",
}),
]);
expect(result.manifest.hooks.map((source) => source.logicalPath)).toContain(
"hooks/crm__session/start.ts",
);
expect(result.manifest.instructions.map((source) => source.logicalPath)).toContain(
"instructions/crm__instructions.md",
);
expect(result.manifest.schedules.map((source) => source.logicalPath)).toContain(
"schedules/crm__daily/sync.ts",
);
expect(result.manifest.skills.map((source) => source.logicalPath)).toContain(
"skills/crm__research.ts",
);
expect(result.manifest.tools.map((source) => [source.logicalPath, source.sourceId])).toEqual(
expect.arrayContaining([
["tools/crm__list.ts", "tools/crm__list.ts"],
["tools/crm__search.ts", "ext-override:crm:tools/search.ts"],
]),
);
expect(result.bindings["ext:crm:tools/list.ts"]).toBeUndefined();
expect(result.bindings["ext-override:crm:tools/search.ts"]).toEqual({
backing: {
externalDependencies: ["@acme/sdk"],
kind: "filesystem",
sourcePath: "/app/agent/extensions/crm/tools/search.ts",
},
logicalPath: "tools/crm__search.ts",
owner: { kind: "application" },
});
});

it("projects extension subagents and preserves their source ownership", () => {
const childRoot = "/packages/crm/extension/subagents/reviewer";
const child = createLocalSubagentSourceRef({
entryPath: childRoot,
logicalPath: "subagents/reviewer",
manifest: createAgentSourceManifest({
agentRoot: childRoot,
appRoot: "/packages/crm",
configModule: createModuleSourceRef({ logicalPath: "agent.ts" }),
}),
rootPath: childRoot,
subagentId: "reviewer",
});
const result = composeAgentSources({
isRoot: true,
manifest: createAgentSourceManifest({
agentRoot: "/app/agent",
appRoot: "/app",
resolvedExtensions: [
{
externalDependencies: [],
manifest: createAgentSourceManifest({
agentRoot: "/packages/crm/extension",
appRoot: "/packages/crm",
subagents: [child],
}),
namespace: "crm",
packageName: "@acme/crm",
packageRoot: "/packages/crm",
sourceRoot: "/packages/crm/extension",
specifier: "@acme/crm",
},
],
}),
nodeId: "root",
registry: frameworkAgentSourceRegistry,
});

const projected = result.manifest.subagents[0]!;
expect(projected).toMatchObject({
logicalPath: "subagents/crm__reviewer",
sourceId: "ext:crm:subagents/reviewer",
subagentId: "crm__reviewer",
});
expect(getSubagentSourceOrigin(projected)).toMatchObject({
layer: "extension-package",
owner: { kind: "extension", namespace: "crm", packageName: "@acme/crm" },
});
});
});
Loading
Loading