veryfront 0.1.758 → 0.1.761
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/esm/cli/commands/init/catalog.d.ts.map +1 -1
- package/esm/cli/commands/init/catalog.js +116 -1
- package/esm/cli/shared/config.d.ts +0 -6
- package/esm/cli/shared/config.d.ts.map +1 -1
- package/esm/cli/shared/config.js +64 -8
- package/esm/cli/templates/integration-loader.d.ts.map +1 -1
- package/esm/cli/templates/integration-loader.js +2 -52
- package/esm/cli/templates/manifest.js +2 -2
- package/esm/deno.d.ts +5 -16
- package/esm/deno.js +6 -17
- package/esm/src/agent/ag-ui/tool-shared.d.ts.map +1 -1
- package/esm/src/agent/ag-ui/tool-shared.js +7 -1
- package/esm/src/agent/child-run/invoke-agent-child-runs.d.ts +0 -1
- package/esm/src/agent/child-run/invoke-agent-child-runs.d.ts.map +1 -1
- package/esm/src/agent/child-run/invoke-agent-child-runs.js +0 -1
- package/esm/src/agent/conversation/bootstrap.d.ts +0 -1
- package/esm/src/agent/conversation/bootstrap.d.ts.map +1 -1
- package/esm/src/agent/conversation/bootstrap.js +0 -1
- package/esm/src/agent/conversation/durable.d.ts +0 -1
- package/esm/src/agent/conversation/durable.d.ts.map +1 -1
- package/esm/src/agent/conversation/durable.js +0 -1
- package/esm/src/agent/factory.d.ts.map +1 -1
- package/esm/src/agent/factory.js +7 -1
- package/esm/src/agent/hosted/chat-preparation.d.ts +1 -1
- package/esm/src/agent/hosted/chat-preparation.d.ts.map +1 -1
- package/esm/src/agent/hosted/chat-preparation.js +17 -3
- package/esm/src/agent/hosted/chat-runtime-contract.d.ts +2 -0
- package/esm/src/agent/hosted/chat-runtime-contract.d.ts.map +1 -1
- package/esm/src/agent/hosted/default-chat-runtime.d.ts +2 -0
- package/esm/src/agent/hosted/default-chat-runtime.d.ts.map +1 -1
- package/esm/src/agent/hosted/default-chat-runtime.js +1 -0
- package/esm/src/agent/hosted/default-project-steering-refresh.js +1 -1
- package/esm/src/agent/hosted/project-steering-adapter.d.ts +7 -0
- package/esm/src/agent/hosted/project-steering-adapter.d.ts.map +1 -1
- package/esm/src/agent/hosted/project-steering-adapter.js +12 -1
- package/esm/src/agent/hosted/veryfront-cloud-agent-service.d.ts +4 -0
- package/esm/src/agent/hosted/veryfront-cloud-agent-service.d.ts.map +1 -1
- package/esm/src/agent/hosted/veryfront-cloud-agent-service.js +14 -12
- package/esm/src/agent/index.d.ts +1 -0
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +1 -0
- package/esm/src/agent/memory/index.d.ts +1 -1
- package/esm/src/agent/memory/index.d.ts.map +1 -1
- package/esm/src/agent/memory/index.js +1 -1
- package/esm/src/agent/memory/memory-interface.d.ts +7 -0
- package/esm/src/agent/memory/memory-interface.d.ts.map +1 -1
- package/esm/src/agent/memory/memory.d.ts +25 -0
- package/esm/src/agent/memory/memory.d.ts.map +1 -1
- package/esm/src/agent/memory/memory.js +38 -0
- package/esm/src/agent/project/context.d.ts +2 -0
- package/esm/src/agent/project/context.d.ts.map +1 -1
- package/esm/src/agent/project/context.js +1 -0
- package/esm/src/agent/project/steering-mutation.d.ts.map +1 -1
- package/esm/src/agent/project/steering-mutation.js +7 -1
- package/esm/src/agent/runtime/agent-definition.d.ts +6 -0
- package/esm/src/agent/runtime/agent-definition.d.ts.map +1 -1
- package/esm/src/agent/runtime/agent-definition.js +46 -0
- package/esm/src/agent/runtime/agent-delegation-names.d.ts +5 -0
- package/esm/src/agent/runtime/agent-delegation-names.d.ts.map +1 -0
- package/esm/src/agent/runtime/agent-delegation-names.js +8 -0
- package/esm/src/agent/runtime/agent-delegation.d.ts +32 -0
- package/esm/src/agent/runtime/agent-delegation.d.ts.map +1 -0
- package/esm/src/agent/runtime/agent-delegation.js +57 -0
- package/esm/src/agent/runtime/agent-markdown-adapter.d.ts.map +1 -1
- package/esm/src/agent/runtime/agent-markdown-adapter.js +24 -0
- package/esm/src/agent/runtime/defaults.d.ts +0 -2
- package/esm/src/agent/runtime/defaults.d.ts.map +1 -1
- package/esm/src/agent/runtime/defaults.js +0 -2
- package/esm/src/agent/runtime/index.d.ts +9 -0
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +45 -20
- package/esm/src/agent/runtime/local-tool.d.ts +6 -0
- package/esm/src/agent/runtime/local-tool.d.ts.map +1 -0
- package/esm/src/agent/runtime/local-tool.js +15 -0
- package/esm/src/agent/runtime/project-skill-catalog.d.ts.map +1 -1
- package/esm/src/agent/runtime/project-skill-catalog.js +67 -0
- package/esm/src/agent/runtime/project-skill-loader.d.ts +9 -0
- package/esm/src/agent/runtime/project-skill-loader.d.ts.map +1 -1
- package/esm/src/agent/runtime/project-skill-loader.js +44 -6
- package/esm/src/agent/runtime/skill-metadata.d.ts +23 -0
- package/esm/src/agent/runtime/skill-metadata.d.ts.map +1 -1
- package/esm/src/agent/runtime/skill-metadata.js +11 -0
- package/esm/src/agent/runtime/tool-helpers.d.ts +3 -1
- package/esm/src/agent/runtime/tool-helpers.d.ts.map +1 -1
- package/esm/src/agent/runtime/tool-helpers.js +45 -11
- package/esm/src/agent/schemas/agent.schema.d.ts +1 -0
- package/esm/src/agent/schemas/agent.schema.d.ts.map +1 -1
- package/esm/src/agent/schemas/agent.schema.js +3 -0
- package/esm/src/agent/service/request-auth-cache.d.ts +0 -1
- package/esm/src/agent/service/request-auth-cache.d.ts.map +1 -1
- package/esm/src/agent/service/request-auth-cache.js +0 -1
- package/esm/src/agent/types.d.ts +8 -0
- package/esm/src/agent/types.d.ts.map +1 -1
- package/esm/src/channels/control-plane.d.ts +1 -0
- package/esm/src/channels/control-plane.d.ts.map +1 -1
- package/esm/src/channels/control-plane.js +4 -2
- package/esm/src/chat/ag-ui.d.ts.map +1 -1
- package/esm/src/chat/conversation.d.ts.map +1 -1
- package/esm/src/chat/final-step-fallback.d.ts.map +1 -1
- package/esm/src/chat/protocol.d.ts.map +1 -1
- package/esm/src/chat/protocol.js +1 -0
- package/esm/src/chat/provider-errors.d.ts.map +1 -1
- package/esm/src/chat/provider-errors.js +0 -1
- package/esm/src/chat/stream-watchdog.d.ts +0 -1
- package/esm/src/chat/stream-watchdog.d.ts.map +1 -1
- package/esm/src/chat/stream-watchdog.js +0 -1
- package/esm/src/config/environment-config.d.ts +1 -0
- package/esm/src/config/environment-config.d.ts.map +1 -1
- package/esm/src/config/environment-config.js +4 -0
- package/esm/src/discovery/agent-scoped-capabilities.d.ts +54 -0
- package/esm/src/discovery/agent-scoped-capabilities.d.ts.map +1 -0
- package/esm/src/discovery/agent-scoped-capabilities.js +228 -0
- package/esm/src/discovery/discovery-engine.d.ts.map +1 -1
- package/esm/src/discovery/discovery-engine.js +19 -15
- package/esm/src/discovery/file-discovery.d.ts +10 -0
- package/esm/src/discovery/file-discovery.d.ts.map +1 -1
- package/esm/src/discovery/file-discovery.js +46 -0
- package/esm/src/discovery/handlers/runtime-agent-markdown-handler.d.ts +12 -0
- package/esm/src/discovery/handlers/runtime-agent-markdown-handler.d.ts.map +1 -1
- package/esm/src/discovery/handlers/runtime-agent-markdown-handler.js +99 -22
- package/esm/src/errors/error-registry/agent.d.ts +2 -0
- package/esm/src/errors/error-registry/agent.d.ts.map +1 -1
- package/esm/src/errors/error-registry/agent.js +8 -0
- package/esm/src/errors/error-registry.d.ts +1 -0
- package/esm/src/errors/error-registry.d.ts.map +1 -1
- package/esm/src/extensions/errors.d.ts +2 -0
- package/esm/src/extensions/errors.d.ts.map +1 -1
- package/esm/src/extensions/errors.js +8 -0
- package/esm/src/extensions/loader.d.ts +9 -6
- package/esm/src/extensions/loader.d.ts.map +1 -1
- package/esm/src/extensions/loader.js +39 -4
- package/esm/src/extensions/orchestrate.d.ts +3 -0
- package/esm/src/extensions/orchestrate.d.ts.map +1 -1
- package/esm/src/extensions/orchestrate.js +3 -1
- package/esm/src/integrations/_data.d.ts.map +1 -1
- package/esm/src/integrations/_data.js +31348 -7875
- package/esm/src/integrations/_tool_summaries.d.ts.map +1 -1
- package/esm/src/integrations/_tool_summaries.js +1737 -11
- package/esm/src/integrations/feature-flags.d.ts +1 -1
- package/esm/src/integrations/feature-flags.d.ts.map +1 -1
- package/esm/src/integrations/feature-flags.js +83 -0
- package/esm/src/integrations/schema.d.ts +129 -4
- package/esm/src/integrations/schema.d.ts.map +1 -1
- package/esm/src/integrations/schema.js +126 -1
- package/esm/src/internal-agents/run-stream.d.ts +4 -0
- package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
- package/esm/src/internal-agents/run-stream.js +18 -5
- package/esm/src/mcp/server.d.ts.map +1 -1
- package/esm/src/mcp/server.js +5 -0
- package/esm/src/platform/adapters/base.d.ts +7 -0
- package/esm/src/platform/adapters/base.d.ts.map +1 -1
- package/esm/src/platform/adapters/runtime/deno/adapter.d.ts.map +1 -1
- package/esm/src/platform/adapters/runtime/deno/adapter.js +7 -2
- package/esm/src/registry/project-scoped-registry-manager.d.ts +7 -0
- package/esm/src/registry/project-scoped-registry-manager.d.ts.map +1 -1
- package/esm/src/registry/project-scoped-registry-manager.js +10 -0
- package/esm/src/registry/scoped-registry-facade.d.ts +2 -0
- package/esm/src/registry/scoped-registry-facade.d.ts.map +1 -1
- package/esm/src/registry/scoped-registry-facade.js +4 -0
- package/esm/src/rendering/layouts/utils/component-loader.d.ts +1 -1
- package/esm/src/rendering/layouts/utils/component-loader.d.ts.map +1 -1
- package/esm/src/rendering/layouts/utils/component-loader.js +82 -3
- package/esm/src/rendering/orchestrator/css-cache.d.ts +3 -0
- package/esm/src/rendering/orchestrator/css-cache.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/css-cache.js +16 -8
- package/esm/src/rendering/orchestrator/mdx.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/mdx.js +12 -1
- package/esm/src/server/bootstrap.d.ts.map +1 -1
- package/esm/src/server/bootstrap.js +3 -0
- package/esm/src/server/handlers/dev/dashboard/api.js +6 -3
- package/esm/src/server/handlers/request/agent-stream.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/agent-stream.handler.js +10 -0
- package/esm/src/server/handlers/request/channel-invoke.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/channel-invoke.handler.js +8 -0
- package/esm/src/server/handlers/request/runtime-shutdown-response.d.ts +13 -0
- package/esm/src/server/handlers/request/runtime-shutdown-response.d.ts.map +1 -0
- package/esm/src/server/handlers/request/runtime-shutdown-response.js +16 -0
- package/esm/src/server/production-server.d.ts.map +1 -1
- package/esm/src/server/production-server.js +7 -1
- package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.d.ts.map +1 -1
- package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.js +2 -2
- package/esm/src/server/shutdown-state.d.ts +16 -0
- package/esm/src/server/shutdown-state.d.ts.map +1 -0
- package/esm/src/server/shutdown-state.js +22 -0
- package/esm/src/skill/index.d.ts +1 -1
- package/esm/src/skill/index.d.ts.map +1 -1
- package/esm/src/skill/index.js +1 -1
- package/esm/src/skill/registry.d.ts +29 -3
- package/esm/src/skill/registry.d.ts.map +1 -1
- package/esm/src/skill/registry.js +57 -8
- package/esm/src/skill/tools.d.ts.map +1 -1
- package/esm/src/skill/tools.js +27 -25
- package/esm/src/skill/types.d.ts +8 -0
- package/esm/src/skill/types.d.ts.map +1 -1
- package/esm/src/tool/executor.d.ts +7 -1
- package/esm/src/tool/executor.d.ts.map +1 -1
- package/esm/src/tool/executor.js +12 -1
- package/esm/src/tool/index.d.ts +1 -1
- package/esm/src/tool/index.d.ts.map +1 -1
- package/esm/src/tool/index.js +1 -1
- package/esm/src/tool/registry.d.ts +1 -0
- package/esm/src/tool/registry.d.ts.map +1 -1
- package/esm/src/tool/registry.js +25 -0
- package/esm/src/tool/types.d.ts +9 -0
- package/esm/src/tool/types.d.ts.map +1 -1
- package/esm/src/utils/constants/cache.d.ts +8 -0
- package/esm/src/utils/constants/cache.d.ts.map +1 -1
- package/esm/src/utils/constants/cache.js +8 -0
- package/esm/src/utils/constants/index.d.ts +1 -1
- package/esm/src/utils/constants/index.d.ts.map +1 -1
- package/esm/src/utils/constants/index.js +1 -1
- package/esm/src/utils/index.d.ts +1 -1
- package/esm/src/utils/index.d.ts.map +1 -1
- package/esm/src/utils/index.js +1 -1
- package/esm/src/utils/lru-wrapper.d.ts +2 -0
- package/esm/src/utils/lru-wrapper.d.ts.map +1 -1
- package/esm/src/utils/lru-wrapper.js +1 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -45
- package/esm/src/chat/compat.d.ts +0 -782
- package/esm/src/chat/compat.d.ts.map +0 -1
- package/esm/src/chat/compat.js +0 -113
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-agent colocated capability registration.
|
|
3
|
+
*
|
|
4
|
+
* Directory-layout agents (`agents/{id}/`) may ship their own tools and
|
|
5
|
+
* skills:
|
|
6
|
+
* - Tools: `agents/{id}/tools/*.ts` → registered into the global tool
|
|
7
|
+
* registry under `{agentId}--{shortName}` with `ownerAgentId` metadata.
|
|
8
|
+
* - Skills: `agents/{id}/SKILL.md` (the agent's own skill, registered under
|
|
9
|
+
* the agent id) and `agents/{id}/skills/<sub>/SKILL.md` (registered under
|
|
10
|
+
* `{agentId}--{sub}`), both with `ownerAgentId` metadata.
|
|
11
|
+
*
|
|
12
|
+
* Discovery here is PURE REGISTRATION: no binding decisions. Visibility and
|
|
13
|
+
* selector resolution (`skills:` / `tools:`, `true` or lists, own short names
|
|
14
|
+
* first) happen at invocation time through the owner-aware resolvers, so flat
|
|
15
|
+
* and directory agents share identical binding semantics.
|
|
16
|
+
*
|
|
17
|
+
* The namespace separator is `--` (decided platform-wide): provider-safe and
|
|
18
|
+
* never confusable with `<provider>__<tool>` integration tool naming.
|
|
19
|
+
*/
|
|
20
|
+
import { toolRegistry } from "../tool/index.js";
|
|
21
|
+
import { parseSkillFrontmatter, validateSkillMetadata } from "../skill/parser.js";
|
|
22
|
+
import { getSkill, registerSkill } from "../skill/registry.js";
|
|
23
|
+
import { SKILL_MD_FILENAME } from "../skill/types.js";
|
|
24
|
+
import { registerTool } from "../mcp/index.js";
|
|
25
|
+
import { ensureError } from "../errors/veryfront-error.js";
|
|
26
|
+
import { filenameToId } from "./discovery-utils.js";
|
|
27
|
+
import { discoveryFileExists, findTypeScriptFiles, listDiscoveryDirectoryEntries, readDiscoveryTextFile, } from "./file-discovery.js";
|
|
28
|
+
import { importModule } from "./transpiler.js";
|
|
29
|
+
const AGENT_TOOLS_SUBDIR = "tools";
|
|
30
|
+
const AGENT_SKILLS_SUBDIR = "skills";
|
|
31
|
+
/** Separator between the agent namespace and the capability short name. */
|
|
32
|
+
export const AGENT_CAPABILITY_NAMESPACE_SEPARATOR = "--";
|
|
33
|
+
/** Provider tool-call names allow only this charset, max 64 chars. */
|
|
34
|
+
const PROVIDER_TOOL_NAME_REGEX = /^[A-Za-z0-9_-]{1,64}$/;
|
|
35
|
+
/** Whether a namespaced tool name is valid for provider tool calls. */
|
|
36
|
+
export function isProviderSafeToolName(name) {
|
|
37
|
+
return PROVIDER_TOOL_NAME_REGEX.test(name);
|
|
38
|
+
}
|
|
39
|
+
const SAFE_PATH_SEGMENT_REGEX = /^[A-Za-z0-9._-]+$/;
|
|
40
|
+
/**
|
|
41
|
+
* Whether a directory/file entry name is a safe single path segment — used
|
|
42
|
+
* before joining it into a filesystem path. Rejects `.` and `..` (which match
|
|
43
|
+
* the permissive name regex) as defense-in-depth against path traversal.
|
|
44
|
+
*/
|
|
45
|
+
export function isSafePathSegment(name) {
|
|
46
|
+
return name !== "." && name !== ".." && SAFE_PATH_SEGMENT_REGEX.test(name);
|
|
47
|
+
}
|
|
48
|
+
/** Sanitizes an agent id into a provider-safe namespace segment. */
|
|
49
|
+
export function sanitizeCapabilityNamespace(agentId) {
|
|
50
|
+
return agentId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
51
|
+
}
|
|
52
|
+
/** Namespaces a capability short name under its owning agent. */
|
|
53
|
+
export function namespaceAgentCapability(agentId, shortName) {
|
|
54
|
+
return `${sanitizeCapabilityNamespace(agentId)}${AGENT_CAPABILITY_NAMESPACE_SEPARATOR}${shortName}`;
|
|
55
|
+
}
|
|
56
|
+
function isTool(value) {
|
|
57
|
+
return value !== null && typeof value === "object" &&
|
|
58
|
+
typeof value.execute === "function";
|
|
59
|
+
}
|
|
60
|
+
function hasExplicitToolId(tool) {
|
|
61
|
+
const generated = tool.__veryfrontGeneratedId;
|
|
62
|
+
if (typeof tool.id !== "string" || tool.id.trim().length === 0) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return generated === undefined || tool.id !== generated;
|
|
66
|
+
}
|
|
67
|
+
function toolShortName(tool, file) {
|
|
68
|
+
return hasExplicitToolId(tool) ? tool.id : filenameToId(file);
|
|
69
|
+
}
|
|
70
|
+
function collectModuleTools(module, file) {
|
|
71
|
+
const tools = new Map();
|
|
72
|
+
const record = module;
|
|
73
|
+
for (const value of Object.values(record ?? {})) {
|
|
74
|
+
if (isTool(value)) {
|
|
75
|
+
tools.set(toolShortName(value, file), value);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return tools;
|
|
79
|
+
}
|
|
80
|
+
function reportShadowedGlobalCapability(input) {
|
|
81
|
+
const global = input.kind === "tool"
|
|
82
|
+
? toolRegistry.get(input.shortName)
|
|
83
|
+
: getSkill(input.shortName);
|
|
84
|
+
if (global && global.ownerAgentId === undefined) {
|
|
85
|
+
input.result?.errors.push({
|
|
86
|
+
file: input.file,
|
|
87
|
+
error: ensureError(`Colocated ${input.kind} "${input.shortName}" of agent "${input.agentId}" shadows the ` +
|
|
88
|
+
`global ${input.kind} id "${input.shortName}": the agent's selector resolves its own ` +
|
|
89
|
+
`${input.kind} first. Rename one to make the reference unambiguous.`),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Registers an agent's colocated `tools/*.ts` into the global tool registry
|
|
95
|
+
* under `{agentId}--{shortName}` with owner metadata. Returns registered ids.
|
|
96
|
+
*/
|
|
97
|
+
export async function registerAgentColocatedTools(input) {
|
|
98
|
+
const toolsDir = `${input.rootPath}/${AGENT_TOOLS_SUBDIR}`;
|
|
99
|
+
if (!(await discoveryFileExists(toolsDir, input.context))) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const files = (await findTypeScriptFiles(toolsDir, input.context)).sort((left, right) => left.localeCompare(right));
|
|
103
|
+
const registeredIds = [];
|
|
104
|
+
const seenThisPass = new Set();
|
|
105
|
+
for (const file of files) {
|
|
106
|
+
try {
|
|
107
|
+
const module = await importModule(file, input.context);
|
|
108
|
+
for (const [shortName, moduleTool] of collectModuleTools(module, file)) {
|
|
109
|
+
const namespaced = namespaceAgentCapability(input.agentId, shortName);
|
|
110
|
+
if (!isProviderSafeToolName(namespaced)) {
|
|
111
|
+
input.result?.errors.push({
|
|
112
|
+
file,
|
|
113
|
+
error: ensureError(`Colocated tool "${shortName}" for agent "${input.agentId}" produces an ` +
|
|
114
|
+
`invalid tool name "${namespaced}" (must match [A-Za-z0-9_-], max 64 chars).`),
|
|
115
|
+
});
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// Two colocated tools resolving to the same short name within one
|
|
119
|
+
// discovery pass is a user error — report it instead of silently
|
|
120
|
+
// keeping the first (a later "unknown tool" with no breadcrumb).
|
|
121
|
+
// A pre-existing registry entry from a previous pass is a normal
|
|
122
|
+
// re-discovery refresh and is overwritten.
|
|
123
|
+
if (seenThisPass.has(namespaced)) {
|
|
124
|
+
input.result?.errors.push({
|
|
125
|
+
file,
|
|
126
|
+
error: ensureError(`Duplicate colocated tool "${shortName}" for agent "${input.agentId}": ` +
|
|
127
|
+
`another tools/ module already registered "${namespaced}"; keeping the first.`),
|
|
128
|
+
});
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
seenThisPass.add(namespaced);
|
|
132
|
+
reportShadowedGlobalCapability({
|
|
133
|
+
kind: "tool",
|
|
134
|
+
agentId: input.agentId,
|
|
135
|
+
shortName,
|
|
136
|
+
file,
|
|
137
|
+
result: input.result,
|
|
138
|
+
});
|
|
139
|
+
registerTool(namespaced, {
|
|
140
|
+
...moduleTool,
|
|
141
|
+
id: namespaced,
|
|
142
|
+
ownerAgentId: input.agentId,
|
|
143
|
+
shortName,
|
|
144
|
+
});
|
|
145
|
+
registeredIds.push(namespaced);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
input.result?.errors.push({ file, error: ensureError(error) });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return registeredIds;
|
|
153
|
+
}
|
|
154
|
+
async function buildSkillFromDir(input) {
|
|
155
|
+
const skillMdPath = `${input.skillDir}/${SKILL_MD_FILENAME}`;
|
|
156
|
+
if (!(await discoveryFileExists(skillMdPath, input.context))) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const content = await readDiscoveryTextFile(skillMdPath, input.context);
|
|
160
|
+
const parsed = await parseSkillFrontmatter(content);
|
|
161
|
+
const metadata = validateSkillMetadata(parsed.frontmatter, input.id);
|
|
162
|
+
return {
|
|
163
|
+
id: input.id,
|
|
164
|
+
metadata,
|
|
165
|
+
rootPath: input.skillDir.replace(/^file:\/\//, ""),
|
|
166
|
+
ownerAgentId: input.ownerAgentId,
|
|
167
|
+
shortName: input.shortName,
|
|
168
|
+
...(input.context.fsAdapter ? { fsAdapter: input.context.fsAdapter } : {}),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Registers an agent's colocated skills into the skill registry with owner
|
|
173
|
+
* metadata. The agent's own `SKILL.md` registers under the agent id; nested
|
|
174
|
+
* `skills/<sub>/SKILL.md` skills register under `{agentId}--{sub}`. Returns
|
|
175
|
+
* registered ids.
|
|
176
|
+
*/
|
|
177
|
+
export async function registerAgentColocatedSkills(input) {
|
|
178
|
+
const candidates = [];
|
|
179
|
+
if (await discoveryFileExists(`${input.rootPath}/${SKILL_MD_FILENAME}`, input.context)) {
|
|
180
|
+
candidates.push({ id: input.agentId, shortName: input.agentId, skillDir: input.rootPath });
|
|
181
|
+
}
|
|
182
|
+
const skillsDir = `${input.rootPath}/${AGENT_SKILLS_SUBDIR}`;
|
|
183
|
+
const entries = (await listDiscoveryDirectoryEntries(skillsDir, input.context)).sort((a, b) => a.name.localeCompare(b.name));
|
|
184
|
+
for (const entry of entries) {
|
|
185
|
+
if (!entry.isDirectory || !isSafePathSegment(entry.name)) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
candidates.push({
|
|
189
|
+
id: namespaceAgentCapability(input.agentId, entry.name),
|
|
190
|
+
shortName: entry.name,
|
|
191
|
+
skillDir: `${skillsDir}/${entry.name}`,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
const registeredIds = [];
|
|
195
|
+
for (const candidate of candidates) {
|
|
196
|
+
try {
|
|
197
|
+
const skill = await buildSkillFromDir({
|
|
198
|
+
id: candidate.id,
|
|
199
|
+
skillDir: candidate.skillDir,
|
|
200
|
+
ownerAgentId: input.agentId,
|
|
201
|
+
shortName: candidate.shortName,
|
|
202
|
+
context: input.context,
|
|
203
|
+
});
|
|
204
|
+
if (!skill) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (candidate.shortName !== input.agentId) {
|
|
208
|
+
reportShadowedGlobalCapability({
|
|
209
|
+
kind: "skill",
|
|
210
|
+
agentId: input.agentId,
|
|
211
|
+
shortName: candidate.shortName,
|
|
212
|
+
file: `${candidate.skillDir}/${SKILL_MD_FILENAME}`,
|
|
213
|
+
result: input.result,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
registerSkill(skill.id, skill);
|
|
217
|
+
input.result?.skills.set(skill.id, skill);
|
|
218
|
+
registeredIds.push(skill.id);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
input.result?.errors.push({
|
|
222
|
+
file: `${candidate.skillDir}/${SKILL_MD_FILENAME}`,
|
|
223
|
+
error: ensureError(error),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return registeredIds;
|
|
228
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery-engine.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/discovery-engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,eAAe,EAEf,eAAe,EAEhB,MAAM,YAAY,CAAC;AAsIpB;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"discovery-engine.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/discovery-engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,eAAe,EAEf,eAAe,EAEhB,MAAM,YAAY,CAAC;AAsIpB;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CA+EnF"}
|
|
@@ -120,6 +120,25 @@ export async function discoverAll(config) {
|
|
|
120
120
|
for (const dir of config.toolDirs ?? ["tools"]) {
|
|
121
121
|
await discoverItems(`${baseDir}/${dir}`, result, context, toolHandler, config.verbose);
|
|
122
122
|
}
|
|
123
|
+
// Clear stale skills before any skill registration so deleted/renamed
|
|
124
|
+
// skills are removed. Global skills are discovered BEFORE agents so that
|
|
125
|
+
// directory-agent colocated skills (registered during agent discovery)
|
|
126
|
+
// survive the clear and owned-short-name shadow diagnostics can see the
|
|
127
|
+
// global ids they shadow.
|
|
128
|
+
skillRegistry.clear();
|
|
129
|
+
// Discover skills (parallel path — markdown-based, not TypeScript import)
|
|
130
|
+
for (const dir of config.skillDirs ?? ["skills"]) {
|
|
131
|
+
const skillResult = await discoverSkills(join(baseDir, dir), context, config.verbose);
|
|
132
|
+
for (const [id, skill] of skillResult.skills) {
|
|
133
|
+
if (result.skills.has(id)) {
|
|
134
|
+
logger.warn(`Duplicate skill "${id}" across discovery roots; keeping first registration`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
registerSkill(id, skill);
|
|
138
|
+
result.skills.set(id, skill);
|
|
139
|
+
}
|
|
140
|
+
result.errors.push(...skillResult.errors.map((e) => ({ file: e.file, error: e.error })));
|
|
141
|
+
}
|
|
123
142
|
// Discover agents
|
|
124
143
|
for (const dir of config.agentDirs ?? ["agents"]) {
|
|
125
144
|
await discoverItems(`${baseDir}/${dir}`, result, context, agentHandler, config.verbose);
|
|
@@ -141,20 +160,5 @@ export async function discoverAll(config) {
|
|
|
141
160
|
for (const dir of config.taskDirs ?? ["tasks"]) {
|
|
142
161
|
await discoverItems(`${baseDir}/${dir}`, result, context, taskHandler, config.verbose);
|
|
143
162
|
}
|
|
144
|
-
// Clear stale skills before rediscovery so deleted/renamed skills are removed.
|
|
145
|
-
skillRegistry.clear();
|
|
146
|
-
// Discover skills (parallel path — markdown-based, not TypeScript import)
|
|
147
|
-
for (const dir of config.skillDirs ?? ["skills"]) {
|
|
148
|
-
const skillResult = await discoverSkills(join(baseDir, dir), context, config.verbose);
|
|
149
|
-
for (const [id, skill] of skillResult.skills) {
|
|
150
|
-
if (result.skills.has(id)) {
|
|
151
|
-
logger.warn(`Duplicate skill "${id}" across discovery roots; keeping first registration`);
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
registerSkill(id, skill);
|
|
155
|
-
result.skills.set(id, skill);
|
|
156
|
-
}
|
|
157
|
-
result.errors.push(...skillResult.errors.map((e) => ({ file: e.file, error: e.error })));
|
|
158
|
-
}
|
|
159
163
|
return result;
|
|
160
164
|
}
|
|
@@ -13,4 +13,14 @@ export declare function findTypeScriptFiles(dir: string, context: FileDiscoveryC
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function findMarkdownFiles(dir: string, context: FileDiscoveryContext): Promise<string[]>;
|
|
15
15
|
export declare function readDiscoveryTextFile(fileUrl: string, context: FileDiscoveryContext): Promise<string>;
|
|
16
|
+
/** A single top-level entry inside a discovery directory. */
|
|
17
|
+
export type DiscoveryDirectoryEntry = {
|
|
18
|
+
name: string;
|
|
19
|
+
isFile: boolean;
|
|
20
|
+
isDirectory: boolean;
|
|
21
|
+
};
|
|
22
|
+
/** Lists the immediate (non-recursive) entries of a discovery directory. */
|
|
23
|
+
export declare function listDiscoveryDirectoryEntries(dir: string, context: FileDiscoveryContext): Promise<DiscoveryDirectoryEntry[]>;
|
|
24
|
+
/** Returns true when a discovery file exists (fsAdapter-aware). */
|
|
25
|
+
export declare function discoveryFileExists(path: string, context: FileDiscoveryContext): Promise<boolean>;
|
|
16
26
|
//# sourceMappingURL=file-discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-discovery.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/file-discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAsEvD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAEnB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAEnB;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CASjB"}
|
|
1
|
+
{"version":3,"file":"file-discovery.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/file-discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAsEvD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAEnB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAEnB;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,6DAA6D;AAC7D,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,4EAA4E;AAC5E,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAkCpC;AAED,mEAAmE;AACnE,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,OAAO,CAAC,CAUlB"}
|
|
@@ -76,3 +76,49 @@ export async function readDiscoveryTextFile(fileUrl, context) {
|
|
|
76
76
|
const { fs } = await getNodeDeps(context);
|
|
77
77
|
return fs.readFileSync(path, "utf-8");
|
|
78
78
|
}
|
|
79
|
+
/** Lists the immediate (non-recursive) entries of a discovery directory. */
|
|
80
|
+
export async function listDiscoveryDirectoryEntries(dir, context) {
|
|
81
|
+
const entries = [];
|
|
82
|
+
try {
|
|
83
|
+
if (context.fsAdapter) {
|
|
84
|
+
if (!(await context.fsAdapter.exists(dir)))
|
|
85
|
+
return entries;
|
|
86
|
+
for await (const entry of context.fsAdapter.readDir(dir)) {
|
|
87
|
+
entries.push({
|
|
88
|
+
name: entry.name,
|
|
89
|
+
isFile: entry.isFile,
|
|
90
|
+
isDirectory: entry.isDirectory,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return entries;
|
|
94
|
+
}
|
|
95
|
+
const { fs } = await getNodeDeps(context);
|
|
96
|
+
if (!fs.existsSync(dir))
|
|
97
|
+
return entries;
|
|
98
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
99
|
+
entries.push({
|
|
100
|
+
name: entry.name,
|
|
101
|
+
isFile: entry.isFile(),
|
|
102
|
+
isDirectory: entry.isDirectory(),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (_) {
|
|
107
|
+
/* expected: directory may not exist or be unreadable */
|
|
108
|
+
return entries;
|
|
109
|
+
}
|
|
110
|
+
return entries;
|
|
111
|
+
}
|
|
112
|
+
/** Returns true when a discovery file exists (fsAdapter-aware). */
|
|
113
|
+
export async function discoveryFileExists(path, context) {
|
|
114
|
+
try {
|
|
115
|
+
if (context.fsAdapter) {
|
|
116
|
+
return await context.fsAdapter.exists(path);
|
|
117
|
+
}
|
|
118
|
+
const { fs } = await getNodeDeps(context);
|
|
119
|
+
return fs.existsSync(path);
|
|
120
|
+
}
|
|
121
|
+
catch (_) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -1,3 +1,15 @@
|
|
|
1
1
|
import type { DiscoveryResult, FileDiscoveryContext } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Discovers markdown agents from a directory.
|
|
4
|
+
*
|
|
5
|
+
* Supports two layouts side by side:
|
|
6
|
+
* - Flat: `agents/{id}.md`
|
|
7
|
+
* - Directory: `agents/{id}/AGENT.md` (+ colocated `SKILL.md` / `skills/` /
|
|
8
|
+
* `tools/`, registered with owner metadata)
|
|
9
|
+
*
|
|
10
|
+
* Binding is NOT decided here: both layouts pass their parsed definition to
|
|
11
|
+
* the same adapter, and the owner-aware resolvers apply one rule for every
|
|
12
|
+
* agent kind at invocation time.
|
|
13
|
+
*/
|
|
2
14
|
export declare function discoverRuntimeAgentMarkdownDefinitions(dir: string, result: DiscoveryResult, context: FileDiscoveryContext): Promise<void>;
|
|
3
15
|
//# sourceMappingURL=runtime-agent-markdown-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-agent-markdown-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/discovery/handlers/runtime-agent-markdown-handler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-agent-markdown-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/discovery/handlers/runtime-agent-markdown-handler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAkKzE;;;;;;;;;;;GAWG;AACH,wBAAsB,uCAAuC,CAC3D,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAmBf"}
|
|
@@ -3,25 +3,82 @@ import { parseRuntimeAgentMarkdownDefinition, } from "../../agent/runtime/agent-
|
|
|
3
3
|
import { agentRegistry, registerAgent } from "../../agent/composition/index.js";
|
|
4
4
|
import { ensureError } from "../../errors/veryfront-error.js";
|
|
5
5
|
import { trackAgentPath } from "../discovery-utils.js";
|
|
6
|
-
import {
|
|
6
|
+
import { discoveryFileExists, listDiscoveryDirectoryEntries, readDiscoveryTextFile, } from "../file-discovery.js";
|
|
7
|
+
import { isSafePathSegment, registerAgentColocatedSkills, registerAgentColocatedTools, sanitizeCapabilityNamespace, } from "../agent-scoped-capabilities.js";
|
|
7
8
|
const MARKDOWN_AGENT_FILE_PATTERN = /^[A-Za-z0-9._-]+\.md$/;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
const DIRECTORY_AGENT_FILENAME = "AGENT.md";
|
|
10
|
+
const RESERVED_TOP_LEVEL_FILENAMES = new Set(["AGENT.md", "SKILL.md"]);
|
|
11
|
+
function getFlatAgentCandidate(dir, fileName) {
|
|
12
|
+
if (RESERVED_TOP_LEVEL_FILENAMES.has(fileName)) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
13
15
|
if (!MARKDOWN_AGENT_FILE_PATTERN.test(fileName)) {
|
|
14
16
|
return null;
|
|
15
17
|
}
|
|
18
|
+
const id = fileName.slice(0, -".md".length);
|
|
19
|
+
// Reject `.`/`..` ids as defense-in-depth against path traversal.
|
|
20
|
+
if (!isSafePathSegment(id)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
16
23
|
return {
|
|
17
|
-
id
|
|
18
|
-
file
|
|
24
|
+
id,
|
|
25
|
+
file: `${dir}/${fileName}`,
|
|
19
26
|
};
|
|
20
27
|
}
|
|
21
|
-
function
|
|
28
|
+
async function getDirectoryAgentCandidate(dir, entryName, context) {
|
|
29
|
+
// Reject `.`/`..` and other non-segment names before joining into a path.
|
|
30
|
+
if (!isSafePathSegment(entryName)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const rootPath = `${dir}/${entryName}`;
|
|
34
|
+
const agentFile = `${rootPath}/${DIRECTORY_AGENT_FILENAME}`;
|
|
35
|
+
if (!(await discoveryFileExists(agentFile, context))) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return { id: entryName, file: agentFile, rootPath };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Registers a directory agent's colocated capabilities. This is PURE
|
|
42
|
+
* REGISTRATION — binding (`skills:` / `tools:` selectors) happens at
|
|
43
|
+
* invocation time via the owner-aware resolvers, identically for flat and
|
|
44
|
+
* directory agents.
|
|
45
|
+
*
|
|
46
|
+
* Two distinct agent ids can sanitize to the same provider-safe namespace
|
|
47
|
+
* (e.g. "a.b" and "a_b" -> "a_b"), which would collide owned capability ids;
|
|
48
|
+
* detected and reported instead of silently overwriting.
|
|
49
|
+
*/
|
|
50
|
+
async function registerColocatedCapabilities(definition, rootPath, result, context, namespaceOwners) {
|
|
51
|
+
const namespace = sanitizeCapabilityNamespace(definition.id);
|
|
52
|
+
const existingOwner = namespaceOwners.get(namespace);
|
|
53
|
+
if (existingOwner !== undefined && existingOwner !== definition.id) {
|
|
54
|
+
result.errors.push({
|
|
55
|
+
file: rootPath,
|
|
56
|
+
error: ensureError(`Agent "${definition.id}" shares the sanitized capability namespace ` +
|
|
57
|
+
`"${namespace}" with agent "${existingOwner}". Rename one to avoid ` +
|
|
58
|
+
`colliding colocated tool/skill ids.`),
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
namespaceOwners.set(namespace, definition.id);
|
|
63
|
+
// Skills and tools live in disjoint subtrees; register them concurrently.
|
|
64
|
+
await Promise.all([
|
|
65
|
+
registerAgentColocatedSkills({ agentId: definition.id, rootPath, context, result }),
|
|
66
|
+
registerAgentColocatedTools({ agentId: definition.id, rootPath, context, result }),
|
|
67
|
+
]);
|
|
68
|
+
}
|
|
69
|
+
async function registerMarkdownAgent(definition, file, rootPath, result, context, namespaceOwners) {
|
|
22
70
|
if (result.agents.has(definition.id)) {
|
|
71
|
+
result.errors.push({
|
|
72
|
+
file,
|
|
73
|
+
error: ensureError(`Duplicate agent id "${definition.id}". An agent with this id was already ` +
|
|
74
|
+
`discovered (e.g. both a flat "${definition.id}.md" and a "${definition.id}/" ` +
|
|
75
|
+
`directory exist); keeping the first.`),
|
|
76
|
+
});
|
|
23
77
|
return;
|
|
24
78
|
}
|
|
79
|
+
if (rootPath) {
|
|
80
|
+
await registerColocatedCapabilities(definition, rootPath, result, context, namespaceOwners);
|
|
81
|
+
}
|
|
25
82
|
const runtimeAgent = createRuntimeAgentFromMarkdownDefinition(definition);
|
|
26
83
|
if (runtimeAgent.id !== definition.id) {
|
|
27
84
|
agentRegistry.delete(runtimeAgent.id);
|
|
@@ -30,22 +87,42 @@ function registerMarkdownAgent(definition, file, result) {
|
|
|
30
87
|
trackAgentPath(definition.id, file);
|
|
31
88
|
result.agents.set(definition.id, runtimeAgent);
|
|
32
89
|
}
|
|
90
|
+
async function discoverMarkdownAgentCandidate(candidate, result, context, namespaceOwners) {
|
|
91
|
+
try {
|
|
92
|
+
const definition = parseRuntimeAgentMarkdownDefinition({
|
|
93
|
+
id: candidate.id,
|
|
94
|
+
content: await readDiscoveryTextFile(candidate.file, context),
|
|
95
|
+
});
|
|
96
|
+
await registerMarkdownAgent(definition, candidate.file, candidate.rootPath, result, context, namespaceOwners);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
result.errors.push({ file: candidate.file, error: ensureError(error) });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Discovers markdown agents from a directory.
|
|
104
|
+
*
|
|
105
|
+
* Supports two layouts side by side:
|
|
106
|
+
* - Flat: `agents/{id}.md`
|
|
107
|
+
* - Directory: `agents/{id}/AGENT.md` (+ colocated `SKILL.md` / `skills/` /
|
|
108
|
+
* `tools/`, registered with owner metadata)
|
|
109
|
+
*
|
|
110
|
+
* Binding is NOT decided here: both layouts pass their parsed definition to
|
|
111
|
+
* the same adapter, and the owner-aware resolvers apply one rule for every
|
|
112
|
+
* agent kind at invocation time.
|
|
113
|
+
*/
|
|
33
114
|
export async function discoverRuntimeAgentMarkdownDefinitions(dir, result, context) {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
115
|
+
const entries = (await listDiscoveryDirectoryEntries(dir, context)).sort((left, right) => left.name.localeCompare(right.name));
|
|
116
|
+
const namespaceOwners = new Map();
|
|
117
|
+
for (const entry of entries) {
|
|
118
|
+
const candidate = entry.isDirectory
|
|
119
|
+
? await getDirectoryAgentCandidate(dir, entry.name, context)
|
|
120
|
+
: entry.isFile
|
|
121
|
+
? getFlatAgentCandidate(dir, entry.name)
|
|
122
|
+
: null;
|
|
37
123
|
if (!candidate) {
|
|
38
124
|
continue;
|
|
39
125
|
}
|
|
40
|
-
|
|
41
|
-
const definition = parseRuntimeAgentMarkdownDefinition({
|
|
42
|
-
id: candidate.id,
|
|
43
|
-
content: await readDiscoveryTextFile(candidate.file, context),
|
|
44
|
-
});
|
|
45
|
-
registerMarkdownAgent(definition, candidate.file, result);
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
result.errors.push({ file: candidate.file, error: ensureError(error) });
|
|
49
|
-
}
|
|
126
|
+
await discoverMarkdownAgentCandidate(candidate, result, context, namespaceOwners);
|
|
50
127
|
}
|
|
51
128
|
}
|
|
@@ -4,6 +4,7 @@ export declare const AGENT_TIMEOUT: import("../types.js").RegisteredError;
|
|
|
4
4
|
export declare const AGENT_INTENT_ERROR: import("../types.js").RegisteredError;
|
|
5
5
|
export declare const ORCHESTRATION_ERROR: import("../types.js").RegisteredError;
|
|
6
6
|
export declare const COST_LIMIT_EXCEEDED: import("../types.js").RegisteredError;
|
|
7
|
+
export declare const TOOL_ID_CONFLICT: import("../types.js").RegisteredError;
|
|
7
8
|
/** Registry fragment for AGENT errors (slug → definition). */
|
|
8
9
|
export declare const AGENT_REGISTRY: {
|
|
9
10
|
readonly "agent-error": import("../types.js").RegisteredError;
|
|
@@ -12,5 +13,6 @@ export declare const AGENT_REGISTRY: {
|
|
|
12
13
|
readonly "agent-intent-error": import("../types.js").RegisteredError;
|
|
13
14
|
readonly "orchestration-error": import("../types.js").RegisteredError;
|
|
14
15
|
readonly "cost-limit-exceeded": import("../types.js").RegisteredError;
|
|
16
|
+
readonly "tool-id-conflict": import("../types.js").RegisteredError;
|
|
15
17
|
};
|
|
16
18
|
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../../src/src/errors/error-registry/agent.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,uCAMtB,CAAC;AAEH,eAAO,MAAM,eAAe,uCAM1B,CAAC;AAEH,eAAO,MAAM,aAAa,uCAMxB,CAAC;AAEH,eAAO,MAAM,kBAAkB,uCAM7B,CAAC;AAEH,eAAO,MAAM,mBAAmB,uCAM9B,CAAC;AAEH,eAAO,MAAM,mBAAmB,uCAM9B,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../../src/src/errors/error-registry/agent.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,uCAMtB,CAAC;AAEH,eAAO,MAAM,eAAe,uCAM1B,CAAC;AAEH,eAAO,MAAM,aAAa,uCAMxB,CAAC;AAEH,eAAO,MAAM,kBAAkB,uCAM7B,CAAC;AAEH,eAAO,MAAM,mBAAmB,uCAM9B,CAAC;AAEH,eAAO,MAAM,mBAAmB,uCAM9B,CAAC;AAEH,eAAO,MAAM,gBAAgB,uCAM3B,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,cAAc;;;;;;;;CAQjB,CAAC"}
|
|
@@ -41,6 +41,13 @@ export const COST_LIMIT_EXCEEDED = defineError({
|
|
|
41
41
|
title: "Cost limit exceeded",
|
|
42
42
|
suggestion: "Wait for the budget period to reset or increase the limit",
|
|
43
43
|
});
|
|
44
|
+
export const TOOL_ID_CONFLICT = defineError({
|
|
45
|
+
slug: "tool-id-conflict",
|
|
46
|
+
category: "AGENT",
|
|
47
|
+
status: 409,
|
|
48
|
+
title: "Tool ID conflict",
|
|
49
|
+
suggestion: "Use a unique tool ID or rename one of the conflicting tools",
|
|
50
|
+
});
|
|
44
51
|
/** Registry fragment for AGENT errors (slug → definition). */
|
|
45
52
|
export const AGENT_REGISTRY = {
|
|
46
53
|
"agent-error": AGENT_ERROR,
|
|
@@ -49,4 +56,5 @@ export const AGENT_REGISTRY = {
|
|
|
49
56
|
"agent-intent-error": AGENT_INTENT_ERROR,
|
|
50
57
|
"orchestration-error": ORCHESTRATION_ERROR,
|
|
51
58
|
"cost-limit-exceeded": COST_LIMIT_EXCEEDED,
|
|
59
|
+
"tool-id-conflict": TOOL_ID_CONFLICT,
|
|
52
60
|
};
|
|
@@ -31,6 +31,7 @@ export declare const ERROR_REGISTRY: {
|
|
|
31
31
|
readonly "agent-intent-error": import("./types.js").RegisteredError;
|
|
32
32
|
readonly "orchestration-error": import("./types.js").RegisteredError;
|
|
33
33
|
readonly "cost-limit-exceeded": import("./types.js").RegisteredError;
|
|
34
|
+
readonly "tool-id-conflict": import("./types.js").RegisteredError;
|
|
34
35
|
readonly "deployment-error": import("./types.js").RegisteredError;
|
|
35
36
|
readonly "platform-error": import("./types.js").RegisteredError;
|
|
36
37
|
readonly "env-var-missing": import("./types.js").RegisteredError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-registry.d.ts","sourceRoot":"","sources":["../../../src/src/errors/error-registry.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAgBhD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"error-registry.d.ts","sourceRoot":"","sources":["../../../src/src/errors/error-registry.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAgBhD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYjB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,cAAc,CAAC;AAEpD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,wCAE7C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,0CAE1D;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,SAAS,EAAE,CAEzC"}
|
|
@@ -11,4 +11,6 @@ export declare const EXTENSION_VALIDATION_ERROR: import("../errors/types.js").Re
|
|
|
11
11
|
export declare const CIRCULAR_DEPENDENCY_ERROR: import("../errors/types.js").RegisteredError;
|
|
12
12
|
/** Shared extension conflict error value. */
|
|
13
13
|
export declare const EXTENSION_CONFLICT_ERROR: import("../errors/types.js").RegisteredError;
|
|
14
|
+
/** Shared extension setup timeout error value. */
|
|
15
|
+
export declare const EXTENSION_SETUP_TIMEOUT_ERROR: import("../errors/types.js").RegisteredError;
|
|
14
16
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/src/extensions/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,4CAA4C;AAC5C,eAAO,MAAM,uBAAuB,8CAMlC,CAAC;AAEH,+CAA+C;AAC/C,eAAO,MAAM,0BAA0B,8CAMrC,CAAC;AAEH,8CAA8C;AAC9C,eAAO,MAAM,yBAAyB,8CAMpC,CAAC;AAEH,6CAA6C;AAC7C,eAAO,MAAM,wBAAwB,8CAMnC,CAAC"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/src/extensions/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,4CAA4C;AAC5C,eAAO,MAAM,uBAAuB,8CAMlC,CAAC;AAEH,+CAA+C;AAC/C,eAAO,MAAM,0BAA0B,8CAMrC,CAAC;AAEH,8CAA8C;AAC9C,eAAO,MAAM,yBAAyB,8CAMpC,CAAC;AAEH,6CAA6C;AAC7C,eAAO,MAAM,wBAAwB,8CAMnC,CAAC;AAEH,kDAAkD;AAClD,eAAO,MAAM,6BAA6B,8CAOxC,CAAC"}
|
|
@@ -36,3 +36,11 @@ export const EXTENSION_CONFLICT_ERROR = defineError({
|
|
|
36
36
|
title: "Conflicting extensions detected",
|
|
37
37
|
suggestion: "Remove or disable one of the conflicting extensions in your configuration",
|
|
38
38
|
});
|
|
39
|
+
/** Shared extension setup timeout error value. */
|
|
40
|
+
export const EXTENSION_SETUP_TIMEOUT_ERROR = defineError({
|
|
41
|
+
slug: "extension-setup-timeout",
|
|
42
|
+
category: "RUNTIME",
|
|
43
|
+
status: 500,
|
|
44
|
+
title: "Extension setup timed out",
|
|
45
|
+
suggestion: "Check the extension's setup() for blocking operations, or increase VF_EXTENSION_SETUP_TIMEOUT_MS",
|
|
46
|
+
});
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extension loader — topological sort, lifecycle management, preset flattening.
|
|
3
|
-
*
|
|
4
|
-
* @module extensions/loader
|
|
5
|
-
*/
|
|
6
1
|
import type { ExtensionLogger, ResolvedExtension } from "./types.js";
|
|
2
|
+
/** Options for {@link ExtensionLoader.setupAll}. */
|
|
3
|
+
export interface SetupAllOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Per-extension setup() timeout in milliseconds.
|
|
6
|
+
* Defaults to 30 000 ms. Pass `0` to disable.
|
|
7
|
+
*/
|
|
8
|
+
setupTimeoutMs?: number;
|
|
9
|
+
}
|
|
7
10
|
/** Implement extension loader. */
|
|
8
11
|
export declare class ExtensionLoader {
|
|
9
12
|
private logger;
|
|
@@ -32,7 +35,7 @@ export declare class ExtensionLoader {
|
|
|
32
35
|
* Run the full setup lifecycle for all extensions.
|
|
33
36
|
* If called while extensions are already loaded, tears them down first.
|
|
34
37
|
*/
|
|
35
|
-
setupAll(extensions: ResolvedExtension[], projectConfig: Record<string, unknown
|
|
38
|
+
setupAll(extensions: ResolvedExtension[], projectConfig: Record<string, unknown>, options?: SetupAllOptions): Promise<void>;
|
|
36
39
|
/**
|
|
37
40
|
* Teardown all loaded extensions in reverse order.
|
|
38
41
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/src/extensions/loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/src/extensions/loader.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAA+B,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAKlG,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,kCAAkC;AAClC,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,MAAM,CAA+B;IAE7C;;;;OAIG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;gBAI5C,MAAM,EAAE,eAAe;IAInC;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE;IAIpE,OAAO,CAAC,mBAAmB;IA8B3B;;;OAGG;IACH,eAAe,CAAC,UAAU,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE;IAyErE;;;OAGG;IACG,QAAQ,CACZ,UAAU,EAAE,iBAAiB,EAAE,EAC/B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtC,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC;IAuHhB;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAmBnC"}
|