forgeos 0.1.0-alpha.2 → 0.1.0-alpha.3
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/AGENTS.md +38 -3
- package/README.md +6 -5
- package/package.json +5 -4
- package/src/forge/_generated/actionSubscriptions.json +2 -2
- package/src/forge/_generated/actionSubscriptions.ts +3 -3
- package/src/forge/_generated/agentAdapterManifest.json +2 -2
- package/src/forge/_generated/agentAdapterManifest.ts +3 -3
- package/src/forge/_generated/agentContract.json +2 -2
- package/src/forge/_generated/agentContract.ts +183 -50
- package/src/forge/_generated/agentQuickstart.md +3 -1
- package/src/forge/_generated/agentTools.json +2 -0
- package/src/forge/_generated/agentTools.md +16 -0
- package/src/forge/_generated/agentTools.ts +12 -0
- package/src/forge/_generated/aiContext.ts +67 -1
- package/src/forge/_generated/aiModels.json +2 -2
- package/src/forge/_generated/aiModels.ts +17 -1
- package/src/forge/_generated/aiProviders.json +1 -1
- package/src/forge/_generated/aiProviders.ts +1 -1
- package/src/forge/_generated/aiRegistry.json +2 -2
- package/src/forge/_generated/aiRegistry.ts +7 -5
- package/src/forge/_generated/api.json +2 -2
- package/src/forge/_generated/api.ts +1 -1
- package/src/forge/_generated/appGraph.json +2 -2
- package/src/forge/_generated/appGraph.ts +288 -180
- package/src/forge/_generated/appMap.md +21 -1
- package/src/forge/_generated/artifactManifest.json +2 -2
- package/src/forge/_generated/artifactManifest.ts +2 -2
- package/src/forge/_generated/authClaims.json +1 -1
- package/src/forge/_generated/authClaims.ts +1 -1
- package/src/forge/_generated/authConfig.json +1 -1
- package/src/forge/_generated/authConfig.ts +1 -1
- package/src/forge/_generated/authContext.ts +1 -1
- package/src/forge/_generated/authRegistry.json +1 -1
- package/src/forge/_generated/authRegistry.ts +1 -1
- package/src/forge/_generated/buildInfo.json +2 -2
- package/src/forge/_generated/buildInfo.ts +4 -4
- package/src/forge/_generated/capabilityMap.json +2 -2
- package/src/forge/_generated/capabilityMap.md +1 -1
- package/src/forge/_generated/capabilityMap.ts +2 -2
- package/src/forge/_generated/client.ts +1 -1
- package/src/forge/_generated/clientApi.ts +1 -1
- package/src/forge/_generated/clientManifest.json +2 -2
- package/src/forge/_generated/clientManifest.ts +3 -3
- package/src/forge/_generated/clientTypes.ts +1 -1
- package/src/forge/_generated/configRegistry.json +1 -1
- package/src/forge/_generated/configRegistry.ts +1 -1
- package/src/forge/_generated/dataGraph.json +2 -2
- package/src/forge/_generated/dataGraph.ts +3 -3
- package/src/forge/_generated/db.json +1 -1
- package/src/forge/_generated/db.ts +1 -1
- package/src/forge/_generated/dbSecurityManifest.json +1 -1
- package/src/forge/_generated/dbSecurityManifest.ts +1 -1
- package/src/forge/_generated/dbSessionContext.json +1 -1
- package/src/forge/_generated/dbSessionContext.ts +1 -1
- package/src/forge/_generated/deployManifest.json +2 -2
- package/src/forge/_generated/deployManifest.ts +7 -7
- package/src/forge/_generated/devManifest.json +2 -2
- package/src/forge/_generated/devManifest.ts +18 -3
- package/src/forge/_generated/envSchema.json +1 -1
- package/src/forge/_generated/envSchema.ts +1 -1
- package/src/forge/_generated/frontendGraph.json +1 -1
- package/src/forge/_generated/frontendGraph.ts +1 -1
- package/src/forge/_generated/importGuards.json +1 -1
- package/src/forge/_generated/importGuards.ts +1 -1
- package/src/forge/_generated/index.ts +2 -1
- package/src/forge/_generated/liveProductionManifest.json +1 -1
- package/src/forge/_generated/liveProductionManifest.ts +1 -1
- package/src/forge/_generated/liveProtocol.json +1 -1
- package/src/forge/_generated/liveProtocol.ts +1 -1
- package/src/forge/_generated/liveQueryRegistry.json +2 -2
- package/src/forge/_generated/liveQueryRegistry.ts +3 -3
- package/src/forge/_generated/liveTransportConfig.json +1 -1
- package/src/forge/_generated/liveTransportConfig.ts +1 -1
- package/src/forge/_generated/makeRegistry.json +2 -2
- package/src/forge/_generated/makeRegistry.ts +16 -2
- package/src/forge/_generated/makeTemplates.json +2 -2
- package/src/forge/_generated/makeTemplates.ts +6 -1
- package/src/forge/_generated/mockMap.json +1 -1
- package/src/forge/_generated/mockMap.ts +1 -1
- package/src/forge/_generated/operationPlaybooks.md +34 -14
- package/src/forge/_generated/packageGraph.json +2 -2
- package/src/forge/_generated/packageGraph.ts +8808 -4723
- package/src/forge/_generated/packageUpgradeRegistry.json +2 -2
- package/src/forge/_generated/packageUpgradeRegistry.ts +2 -2
- package/src/forge/_generated/permissionMatrix.json +2 -2
- package/src/forge/_generated/permissionMatrix.ts +3 -3
- package/src/forge/_generated/policyRegistry.json +2 -2
- package/src/forge/_generated/policyRegistry.ts +3 -3
- package/src/forge/_generated/queryRegistry.json +2 -2
- package/src/forge/_generated/queryRegistry.ts +3 -3
- package/src/forge/_generated/react.d.ts +1 -1
- package/src/forge/_generated/react.ts +1 -1
- package/src/forge/_generated/reactManifest.json +2 -2
- package/src/forge/_generated/reactManifest.ts +3 -3
- package/src/forge/_generated/releaseManifest.json +2 -2
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/_generated/rlsPolicies.json +1 -1
- package/src/forge/_generated/rlsPolicies.sql +1 -1
- package/src/forge/_generated/rlsPolicies.ts +1 -1
- package/src/forge/_generated/runtimeGraph.json +2 -2
- package/src/forge/_generated/runtimeGraph.ts +3 -3
- package/src/forge/_generated/runtimeMatrix.json +2 -2
- package/src/forge/_generated/runtimeMatrix.ts +8684 -1939
- package/src/forge/_generated/runtimeRegistry.ts +1 -1
- package/src/forge/_generated/runtimeRules.md +13 -1
- package/src/forge/_generated/secretRegistry.json +1 -1
- package/src/forge/_generated/secretRegistry.ts +1 -1
- package/src/forge/_generated/secretsContext.ts +1 -1
- package/src/forge/_generated/serverApi.ts +1 -1
- package/src/forge/_generated/sourceMapManifest.json +2 -2
- package/src/forge/_generated/sourceMapManifest.ts +2 -2
- package/src/forge/_generated/sqlPlan.json +1 -1
- package/src/forge/_generated/sqlPlan.ts +1 -1
- package/src/forge/_generated/subscriptionManifest.json +2 -2
- package/src/forge/_generated/subscriptionManifest.ts +3 -3
- package/src/forge/_generated/symbolicationManifest.json +2 -2
- package/src/forge/_generated/symbolicationManifest.ts +2 -2
- package/src/forge/_generated/telemetryRegistry.json +2 -2
- package/src/forge/_generated/telemetryRegistry.ts +3 -3
- package/src/forge/_generated/telemetrySinks.json +2 -2
- package/src/forge/_generated/telemetrySinks.ts +2 -2
- package/src/forge/_generated/tenantScope.json +2 -2
- package/src/forge/_generated/tenantScope.ts +3 -3
- package/src/forge/_generated/testGraph.json +2 -2
- package/src/forge/_generated/testGraph.ts +17 -7
- package/src/forge/_generated/testPlanRegistry.json +2 -2
- package/src/forge/_generated/testPlanRegistry.ts +2 -2
- package/src/forge/_generated/uiRoutes.json +1 -1
- package/src/forge/_generated/uiRoutes.ts +1 -1
- package/src/forge/_generated/uiScenarios.json +1 -1
- package/src/forge/_generated/uiScenarios.ts +1 -1
- package/src/forge/_generated/uiTestManifest.json +2 -2
- package/src/forge/_generated/uiTestManifest.ts +2 -2
- package/src/forge/_generated/workflowRegistry.json +2 -2
- package/src/forge/_generated/workflowRegistry.ts +3 -3
- package/src/forge/_generated/workflowSubscriptions.json +2 -2
- package/src/forge/_generated/workflowSubscriptions.ts +3 -3
- package/src/forge/cli/ai.ts +186 -1
- package/src/forge/cli/commands.ts +5 -0
- package/src/forge/cli/parse.ts +30 -3
- package/src/forge/compiler/agent-contract/build.ts +281 -8
- package/src/forge/compiler/agent-contract/types.ts +41 -0
- package/src/forge/compiler/ai-registry/build.ts +62 -1
- package/src/forge/compiler/ai-registry/constants.ts +1 -1
- package/src/forge/compiler/ai-registry/parse.ts +98 -4
- package/src/forge/compiler/app-graph/forge-apis.ts +1 -0
- package/src/forge/compiler/dev-manifest/build.ts +3 -0
- package/src/forge/compiler/make-registry/build.ts +13 -0
- package/src/forge/compiler/orchestrator/plan.ts +11 -0
- package/src/forge/compiler/orchestrator/serialize.ts +68 -0
- package/src/forge/compiler/types/ai-registry.ts +25 -1
- package/src/forge/compiler/types/app-graph.ts +1 -0
- package/src/forge/compiler/types/cli.ts +1 -0
- package/src/forge/compiler/types/dev-manifest.ts +3 -0
- package/src/forge/dev/server.ts +508 -1
- package/src/forge/make/index.ts +126 -3
- package/src/forge/make/templates.ts +188 -0
- package/src/forge/make/types.ts +1 -0
- package/src/forge/runtime/ai/context.ts +210 -5
- package/src/forge/runtime/ai/types.ts +70 -0
- package/src/forge/runtime/context/create-context.ts +30 -6
- package/src/forge/server.ts +82 -0
- package/src/forge/version.ts +1 -1
|
@@ -46,6 +46,7 @@ import type {
|
|
|
46
46
|
AgentHttpEndpointInfo,
|
|
47
47
|
AgentIntegrationInfo,
|
|
48
48
|
AgentRuntimeRule,
|
|
49
|
+
AgentToolRegistry,
|
|
49
50
|
AgentPlaybook,
|
|
50
51
|
} from "./types.ts";
|
|
51
52
|
|
|
@@ -78,9 +79,11 @@ export interface AgentContractInput {
|
|
|
78
79
|
export interface AgentContractArtifacts {
|
|
79
80
|
contract: AgentContract;
|
|
80
81
|
capabilityMap: AgentCapabilityMap;
|
|
82
|
+
toolRegistry: AgentToolRegistry;
|
|
81
83
|
agentsMd: string;
|
|
82
84
|
appMapMd: string;
|
|
83
85
|
capabilityMapMd: string;
|
|
86
|
+
agentToolsMd: string;
|
|
84
87
|
runtimeRulesMd: string;
|
|
85
88
|
operationPlaybooksMd: string;
|
|
86
89
|
agentQuickstartMd: string;
|
|
@@ -245,26 +248,26 @@ function runtimeRules(): AgentRuntimeRule[] {
|
|
|
245
248
|
{
|
|
246
249
|
context: "command",
|
|
247
250
|
allowed: ["ctx.db writes", "ctx.emit", "ctx.telemetry buffered events"],
|
|
248
|
-
forbidden: ["network packages", "ctx.secrets", "ctx.ai", "process.env", "filesystem access"],
|
|
251
|
+
forbidden: ["network packages", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "process.env", "filesystem access"],
|
|
249
252
|
},
|
|
250
253
|
{
|
|
251
254
|
context: "query",
|
|
252
255
|
allowed: ["ctx.db reads", "ctx.telemetry buffered events"],
|
|
253
|
-
forbidden: ["insert/update/delete", "ctx.emit", "ctx.secrets", "ctx.ai", "network integrations"],
|
|
256
|
+
forbidden: ["insert/update/delete", "ctx.emit", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "network integrations"],
|
|
254
257
|
},
|
|
255
258
|
{
|
|
256
259
|
context: "liveQuery",
|
|
257
260
|
allowed: ["ctx.db reads", "tenant-scoped subscriptions"],
|
|
258
|
-
forbidden: ["insert/update/delete", "ctx.emit", "ctx.secrets", "ctx.ai", "network integrations"],
|
|
261
|
+
forbidden: ["insert/update/delete", "ctx.emit", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "network integrations"],
|
|
259
262
|
},
|
|
260
263
|
{
|
|
261
264
|
context: "action",
|
|
262
|
-
allowed: ["ctx.secrets", "integrations", "ctx.ai", "ctx.db reads/writes", "network packages"],
|
|
265
|
+
allowed: ["ctx.secrets", "integrations", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "AI SDK tools", "ctx.db reads/writes", "network packages"],
|
|
263
266
|
forbidden: ["uncommitted transactional side effects"],
|
|
264
267
|
},
|
|
265
268
|
{
|
|
266
269
|
context: "workflow",
|
|
267
|
-
allowed: ["durable steps", "ctx.secrets", "integrations", "ctx.ai", "retries"],
|
|
270
|
+
allowed: ["durable steps", "ctx.secrets", "integrations", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "AI SDK ToolLoopAgent", "retries"],
|
|
268
271
|
forbidden: ["non-idempotent step behavior without guards"],
|
|
269
272
|
},
|
|
270
273
|
];
|
|
@@ -320,6 +323,28 @@ function playbooks(): AgentPlaybook[] {
|
|
|
320
323
|
"Reconnect with Last-Event-ID or ?lastRevision=<revision> to verify resume behavior.",
|
|
321
324
|
],
|
|
322
325
|
},
|
|
326
|
+
{
|
|
327
|
+
title: "Add an AI tool",
|
|
328
|
+
steps: [
|
|
329
|
+
"Add a server-only file under src/ai or src/tools.",
|
|
330
|
+
"Export aiTool({ description, inputSchema, outputSchema, risk, needsApproval, handler }).",
|
|
331
|
+
"Use zod schemas for inputSchema and outputSchema.",
|
|
332
|
+
"Access secrets through the tool context, not process.env.",
|
|
333
|
+
"Mark destructive or external side effects with risk and needsApproval.",
|
|
334
|
+
"Run forge generate and inspect src/forge/_generated/aiRegistry.json.",
|
|
335
|
+
],
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
title: "Add an agent",
|
|
339
|
+
steps: [
|
|
340
|
+
"Export agent({ provider, model, instructions, tools, stopWhen }) from server-only source.",
|
|
341
|
+
"Prefer AI SDK ToolLoopAgent semantics through ctx.agent.run or ctx.ai.runAgent instead of custom loops.",
|
|
342
|
+
"Use stopWhen with stepCount or terminal tool calls to prevent unbounded loops.",
|
|
343
|
+
"Run agents only in actions, workflows, endpoints, or server code.",
|
|
344
|
+
"Run forge inspect all --json and confirm agentContract.ai.agents lists the agent.",
|
|
345
|
+
"Use forge ai trace <traceId> --json to inspect agent runs and tool calls.",
|
|
346
|
+
],
|
|
347
|
+
},
|
|
323
348
|
{
|
|
324
349
|
title: "Add a table",
|
|
325
350
|
steps: [
|
|
@@ -355,7 +380,8 @@ function playbooks(): AgentPlaybook[] {
|
|
|
355
380
|
title: "Safely refactor a feature",
|
|
356
381
|
steps: [
|
|
357
382
|
"Run forge refactor rename field <table.field> <table.field> --dry-run --json.",
|
|
358
|
-
"
|
|
383
|
+
"Run forge refactor rename command <oldName> <newName> --dry-run --json when renaming runtime entrypoints.",
|
|
384
|
+
"Rename codemods are AST-aware for extract-action, rename command, rename field, and rename table.",
|
|
359
385
|
"Field renames are scoped to the target table, so tickets.priority only rewrites references linked to tickets.",
|
|
360
386
|
"Review filesToModify, migrationPlan, diagnostics, and risk.",
|
|
361
387
|
"Use --allow-high-risk only for intentional high-risk refactors.",
|
|
@@ -428,6 +454,7 @@ function playbooks(): AgentPlaybook[] {
|
|
|
428
454
|
title: "Add or update frontend",
|
|
429
455
|
steps: [
|
|
430
456
|
"Run forge make ui --framework vite --dry-run --json when the app does not have a web root.",
|
|
457
|
+
"Run forge make ai-chat support --dry-run --json to add a chat surface backed by /ai/agents/chat streaming and /ai/agents/run JSON automation.",
|
|
431
458
|
"Use web/lib/forge.ts as the generated client bridge.",
|
|
432
459
|
"Mount ForgeProvider once in the web app provider/layout layer; use devAuth for local development.",
|
|
433
460
|
"Use useQuery, useCommand, and useLiveQuery instead of raw /commands or /queries fetches.",
|
|
@@ -656,6 +683,72 @@ function buildCapabilityMap(contract: AgentContract): AgentCapabilityMap {
|
|
|
656
683
|
};
|
|
657
684
|
}
|
|
658
685
|
|
|
686
|
+
function autoToolName(kind: "command" | "query" | "liveQuery", name: string): string {
|
|
687
|
+
return `forge_${kind}_${name}`.replace(/[^A-Za-z0-9_$]/g, "_");
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function buildAgentToolRegistry(contract: AgentContract): AgentToolRegistry {
|
|
691
|
+
const autoTools: AgentToolRegistry["autoTools"] = [
|
|
692
|
+
...contract.commands.map((command) => ({
|
|
693
|
+
name: autoToolName("command", command.name),
|
|
694
|
+
sourceKind: "command" as const,
|
|
695
|
+
sourceName: command.name,
|
|
696
|
+
...(command.policy ? { policy: command.policy } : {}),
|
|
697
|
+
file: command.file,
|
|
698
|
+
http: command.http,
|
|
699
|
+
frontend: command.frontend,
|
|
700
|
+
tablesRead: command.tablesRead,
|
|
701
|
+
tablesWritten: command.tablesWritten,
|
|
702
|
+
emits: command.emits,
|
|
703
|
+
dependencies: [],
|
|
704
|
+
readOnly: false,
|
|
705
|
+
requiresAuth: command.policy !== undefined && command.policy !== "public",
|
|
706
|
+
execution: "forge-runtime-endpoint" as const,
|
|
707
|
+
})),
|
|
708
|
+
...contract.queries.map((query) => ({
|
|
709
|
+
name: autoToolName("query", query.name),
|
|
710
|
+
sourceKind: "query" as const,
|
|
711
|
+
sourceName: query.name,
|
|
712
|
+
...(query.policy ? { policy: query.policy } : {}),
|
|
713
|
+
file: query.file,
|
|
714
|
+
http: query.http,
|
|
715
|
+
frontend: query.frontend,
|
|
716
|
+
tablesRead: query.tablesRead,
|
|
717
|
+
tablesWritten: [],
|
|
718
|
+
emits: [],
|
|
719
|
+
dependencies: [],
|
|
720
|
+
readOnly: true,
|
|
721
|
+
requiresAuth: query.policy !== undefined && query.policy !== "public",
|
|
722
|
+
execution: "forge-runtime-endpoint" as const,
|
|
723
|
+
})),
|
|
724
|
+
...contract.liveQueries.map((liveQuery) => ({
|
|
725
|
+
name: autoToolName("liveQuery", liveQuery.name),
|
|
726
|
+
sourceKind: "liveQuery" as const,
|
|
727
|
+
sourceName: liveQuery.name,
|
|
728
|
+
...(liveQuery.policy ? { policy: liveQuery.policy } : {}),
|
|
729
|
+
file: liveQuery.file,
|
|
730
|
+
http: liveQuery.http,
|
|
731
|
+
frontend: liveQuery.frontend,
|
|
732
|
+
tablesRead: liveQuery.tablesRead,
|
|
733
|
+
tablesWritten: [],
|
|
734
|
+
emits: [],
|
|
735
|
+
dependencies: liveQuery.dependencies,
|
|
736
|
+
readOnly: true,
|
|
737
|
+
requiresAuth: liveQuery.policy !== undefined && liveQuery.policy !== "public",
|
|
738
|
+
execution: "forge-runtime-endpoint" as const,
|
|
739
|
+
})),
|
|
740
|
+
].sort((a, b) => a.name.localeCompare(b.name));
|
|
741
|
+
|
|
742
|
+
return {
|
|
743
|
+
schemaVersion: "0.1.0",
|
|
744
|
+
generatorVersion: GENERATOR_VERSION,
|
|
745
|
+
project: contract.project,
|
|
746
|
+
explicitTools: contract.ai.tools,
|
|
747
|
+
autoTools,
|
|
748
|
+
agents: contract.ai.agents,
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
|
|
659
752
|
function jsAccess(group: string, name: string): string {
|
|
660
753
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name)
|
|
661
754
|
? `api.${group}.${name}`
|
|
@@ -951,6 +1044,23 @@ export function buildAgentContractArtifacts(
|
|
|
951
1044
|
...(generation.purpose ? { purpose: generation.purpose } : {}),
|
|
952
1045
|
}))
|
|
953
1046
|
.sort((a, b) => `${a.file}:${a.method}:${a.model}`.localeCompare(`${b.file}:${b.method}:${b.model}`)),
|
|
1047
|
+
tools: input.aiRegistry.tools.map((tool) => ({
|
|
1048
|
+
name: tool.name,
|
|
1049
|
+
file: tool.file,
|
|
1050
|
+
...(tool.description ? { description: tool.description } : {}),
|
|
1051
|
+
risk: tool.risk,
|
|
1052
|
+
strict: tool.strict,
|
|
1053
|
+
needsApproval: tool.needsApproval,
|
|
1054
|
+
})),
|
|
1055
|
+
agents: input.aiRegistry.agents.map((agent) => ({
|
|
1056
|
+
name: agent.name,
|
|
1057
|
+
file: agent.file,
|
|
1058
|
+
provider: agent.provider,
|
|
1059
|
+
model: agent.model,
|
|
1060
|
+
...(agent.instructions ? { instructions: agent.instructions } : {}),
|
|
1061
|
+
tools: agent.tools,
|
|
1062
|
+
stopWhen: agent.stopWhen,
|
|
1063
|
+
})),
|
|
954
1064
|
},
|
|
955
1065
|
client: {
|
|
956
1066
|
queries: input.clientManifest.queries,
|
|
@@ -1038,14 +1148,17 @@ export function buildAgentContractArtifacts(
|
|
|
1038
1148
|
: null;
|
|
1039
1149
|
const userNotes = extractUserNotes(existingAgents);
|
|
1040
1150
|
const agentsMd = renderAgentsMd(contract, userNotes);
|
|
1151
|
+
const toolRegistry = buildAgentToolRegistry(contract);
|
|
1041
1152
|
const capabilityMap = buildCapabilityMap(contract);
|
|
1042
1153
|
const capabilityMapMd = renderCapabilityMapMd(capabilityMap);
|
|
1154
|
+
const agentToolsMd = renderAgentToolsMd(toolRegistry);
|
|
1043
1155
|
const appMapMd = renderAppMapMd(contract);
|
|
1044
1156
|
const runtimeRulesMd = renderRuntimeRulesMd(contract.rules);
|
|
1045
1157
|
const operationPlaybooksMd = renderOperationPlaybooksMd(contract.playbooks);
|
|
1046
1158
|
const agentQuickstartMd = renderAgentQuickstartMd();
|
|
1047
1159
|
const diagnostics = scanAgentContractForLeaks(contract, [
|
|
1048
1160
|
agentsMd,
|
|
1161
|
+
agentToolsMd,
|
|
1049
1162
|
capabilityMapMd,
|
|
1050
1163
|
appMapMd,
|
|
1051
1164
|
runtimeRulesMd,
|
|
@@ -1056,9 +1169,11 @@ export function buildAgentContractArtifacts(
|
|
|
1056
1169
|
return {
|
|
1057
1170
|
contract,
|
|
1058
1171
|
capabilityMap,
|
|
1172
|
+
toolRegistry,
|
|
1059
1173
|
agentsMd,
|
|
1060
1174
|
appMapMd,
|
|
1061
1175
|
capabilityMapMd,
|
|
1176
|
+
agentToolsMd,
|
|
1062
1177
|
runtimeRulesMd,
|
|
1063
1178
|
operationPlaybooksMd,
|
|
1064
1179
|
agentQuickstartMd,
|
|
@@ -1099,6 +1214,15 @@ export function serializeCapabilityMapTs(capabilityMap: AgentCapabilityMap): str
|
|
|
1099
1214
|
return `export const capabilityMap = ${JSON.stringify(parsed, null, 2)} as const;\n`;
|
|
1100
1215
|
}
|
|
1101
1216
|
|
|
1217
|
+
export function serializeAgentToolRegistryJson(registry: AgentToolRegistry): string {
|
|
1218
|
+
return serializeCanonical(registry);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
export function serializeAgentToolRegistryTs(registry: AgentToolRegistry): string {
|
|
1222
|
+
const parsed = JSON.parse(serializeAgentToolRegistryJson(registry)) as unknown;
|
|
1223
|
+
return `export const agentTools = ${JSON.stringify(parsed, null, 2)} as const;\n`;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1102
1226
|
function renderAgentsMd(contract: AgentContract, userNotes: string): string {
|
|
1103
1227
|
const tenantTables = contract.data.tables
|
|
1104
1228
|
.filter((table) => table.tenantScoped)
|
|
@@ -1107,6 +1231,12 @@ function renderAgentsMd(contract: AgentContract, userNotes: string): string {
|
|
|
1107
1231
|
`${policy.name}: ${policy.roles.length > 0 ? policy.roles.join(", ") : policy.kind}`,
|
|
1108
1232
|
);
|
|
1109
1233
|
const secrets = contract.secrets.map((secret) => `${secret.name}${secret.required ? " (required)" : " (optional)"}`);
|
|
1234
|
+
const aiTools = contract.ai.tools.map((tool) =>
|
|
1235
|
+
`${tool.name}: ${tool.description ?? "no description"} (${tool.risk}${tool.needsApproval ? ", approval" : ""})`,
|
|
1236
|
+
);
|
|
1237
|
+
const aiAgents = contract.ai.agents.map((agent) =>
|
|
1238
|
+
`${agent.name}: ${agent.provider}/${agent.model} with ${agent.tools.length > 0 ? agent.tools.join(", ") : "no tools"}`,
|
|
1239
|
+
);
|
|
1110
1240
|
|
|
1111
1241
|
return normalizeNewlines(`# AGENTS.md
|
|
1112
1242
|
|
|
@@ -1178,6 +1308,7 @@ forge inspect app --json
|
|
|
1178
1308
|
forge inspect all --json
|
|
1179
1309
|
forge inspect frontend --json
|
|
1180
1310
|
forge inspect capabilities --json
|
|
1311
|
+
forge inspect agent-tools --json
|
|
1181
1312
|
forge deps inspect <package> --json
|
|
1182
1313
|
forge deps api <package> <symbol> --json
|
|
1183
1314
|
forge deps trace <package> --json
|
|
@@ -1191,6 +1322,9 @@ forge doctor
|
|
|
1191
1322
|
forge doctor windows --json
|
|
1192
1323
|
forge setup windows --json
|
|
1193
1324
|
forge agent print-context --json
|
|
1325
|
+
forge ai tools --json
|
|
1326
|
+
forge ai agents --json
|
|
1327
|
+
forge ai trace <traceId> --json
|
|
1194
1328
|
forge verify --smoke
|
|
1195
1329
|
forge verify --standard
|
|
1196
1330
|
forge verify --strict
|
|
@@ -1210,6 +1344,21 @@ ${renderList(policies)}
|
|
|
1210
1344
|
|
|
1211
1345
|
${renderList(secrets)}
|
|
1212
1346
|
|
|
1347
|
+
## AI Tools And Agents
|
|
1348
|
+
|
|
1349
|
+
- AI SDK engine: Vercel AI SDK v6.
|
|
1350
|
+
- Forge layer: generated registry, runtime rules, telemetry, secrets, tenant/auth context, and agent contract.
|
|
1351
|
+
- Use \`ctx.agent.run\` or \`ctx.ai.runAgent\` only in actions, workflows, endpoints, and server code.
|
|
1352
|
+
- Do not create custom tool loops; use Forge tools and AI SDK \`ToolLoopAgent\` through the Forge runtime.
|
|
1353
|
+
|
|
1354
|
+
Tools:
|
|
1355
|
+
|
|
1356
|
+
${renderList(aiTools)}
|
|
1357
|
+
|
|
1358
|
+
Agents:
|
|
1359
|
+
|
|
1360
|
+
${renderList(aiAgents)}
|
|
1361
|
+
|
|
1213
1362
|
## Auth
|
|
1214
1363
|
|
|
1215
1364
|
- Modes: ${contract.auth.modes.join(", ")}
|
|
@@ -1268,6 +1417,7 @@ Use:
|
|
|
1268
1417
|
forge make resource <name> --fields title:text,status:enum(open,closed) --dry-run --json
|
|
1269
1418
|
forge make resource <name> --fields title:text,status:enum(open,closed) --with-ui --yes
|
|
1270
1419
|
forge make ui --framework vite --dry-run --json
|
|
1420
|
+
forge make ai-chat support --dry-run --json
|
|
1271
1421
|
\`\`\`
|
|
1272
1422
|
|
|
1273
1423
|
Review the plan before applying when the resource touches schema or policies.
|
|
@@ -1304,11 +1454,13 @@ Use:
|
|
|
1304
1454
|
\`\`\`bash
|
|
1305
1455
|
forge refactor rename field tickets.priority tickets.urgency --dry-run --json
|
|
1306
1456
|
forge refactor rename field tickets.priority tickets.urgency --yes
|
|
1457
|
+
forge refactor rename command createTicket openTicket --dry-run --json
|
|
1458
|
+
forge refactor rename command createTicket openTicket --yes
|
|
1307
1459
|
\`\`\`
|
|
1308
1460
|
|
|
1309
|
-
These codemods are AST-aware for \`extract-action\`, \`rename field\`, and \`rename table\`. Field renames are scoped to the target table, so \`tickets.priority\` only rewrites references linked to \`tickets\`.
|
|
1461
|
+
These codemods are AST-aware for \`extract-action\`, \`rename command\`, \`rename field\`, and \`rename table\`. Command renames update runtime registries, generated client references, frontend hooks, tests, and string references where safe. Field renames are scoped to the target table, so \`tickets.priority\` only rewrites references linked to \`tickets\`.
|
|
1310
1462
|
|
|
1311
|
-
Never edit \`src/forge/_generated/**\` directly. Review migration hints before applying field or table renames.
|
|
1463
|
+
Never edit \`src/forge/_generated/**\` directly. Review migration hints before applying command, field, or table renames.
|
|
1312
1464
|
|
|
1313
1465
|
### Plan impact-based tests
|
|
1314
1466
|
|
|
@@ -1334,6 +1486,19 @@ forge repair plan --from-last-test-run --write
|
|
|
1334
1486
|
|
|
1335
1487
|
Apply only high-confidence deterministic repairs automatically. Review medium or low confidence repairs before changing code.
|
|
1336
1488
|
|
|
1489
|
+
### Add AI tools or agents
|
|
1490
|
+
|
|
1491
|
+
Use:
|
|
1492
|
+
|
|
1493
|
+
\`\`\`bash
|
|
1494
|
+
forge generate
|
|
1495
|
+
forge inspect all --json
|
|
1496
|
+
forge ai check --json
|
|
1497
|
+
forge ai trace <traceId> --json
|
|
1498
|
+
\`\`\`
|
|
1499
|
+
|
|
1500
|
+
Define tools with \`aiTool({ inputSchema, outputSchema, risk, needsApproval, handler })\` and agents with \`agent({ provider, model, instructions, tools, stopWhen })\`. Execute agents with \`ctx.agent.run\` or \`ctx.ai.runAgent\` only from actions, workflows, endpoints, or server code. In dev, POST \`/ai/agents/run\` returns JSON for automation and POST \`/ai/agents/chat\` returns an AI SDK UIMessage stream for React \`useChat\`; both accept \`agent: "<exportedAgentName>"\` and use generated auto-tools from \`agentTools.json\`.
|
|
1501
|
+
|
|
1337
1502
|
### Export agent adapters
|
|
1338
1503
|
|
|
1339
1504
|
Use:
|
|
@@ -1471,6 +1636,48 @@ function renderAppMapMd(contract: AgentContract): string {
|
|
|
1471
1636
|
lines.push(`### ${workflow.name}`, `Trigger: ${workflow.trigger ?? "manual"}`, "Steps:", ...renderList(workflow.steps).split("\n"), "");
|
|
1472
1637
|
}
|
|
1473
1638
|
|
|
1639
|
+
lines.push("## AI", "");
|
|
1640
|
+
lines.push("### Providers", "", ...renderList(contract.ai.providers).split("\n"), "");
|
|
1641
|
+
lines.push("### Generations", "");
|
|
1642
|
+
for (const generation of contract.ai.generations) {
|
|
1643
|
+
lines.push(
|
|
1644
|
+
`- ${generation.method}: ${generation.provider}/${generation.model} in ${generation.file}${generation.purpose ? ` (${generation.purpose})` : ""}`,
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
if (contract.ai.generations.length === 0) {
|
|
1648
|
+
lines.push("- none");
|
|
1649
|
+
}
|
|
1650
|
+
lines.push("", "### Tools", "");
|
|
1651
|
+
for (const tool of contract.ai.tools) {
|
|
1652
|
+
lines.push(
|
|
1653
|
+
`#### ${tool.name}`,
|
|
1654
|
+
`File: ${tool.file}`,
|
|
1655
|
+
`Risk: ${tool.risk}`,
|
|
1656
|
+
`Strict: ${tool.strict ? "yes" : "no"}`,
|
|
1657
|
+
`Needs approval: ${String(tool.needsApproval)}`,
|
|
1658
|
+
`Description: ${tool.description ?? "none"}`,
|
|
1659
|
+
"",
|
|
1660
|
+
);
|
|
1661
|
+
}
|
|
1662
|
+
if (contract.ai.tools.length === 0) {
|
|
1663
|
+
lines.push("- none", "");
|
|
1664
|
+
}
|
|
1665
|
+
lines.push("### Agents", "");
|
|
1666
|
+
for (const agent of contract.ai.agents) {
|
|
1667
|
+
lines.push(
|
|
1668
|
+
`#### ${agent.name}`,
|
|
1669
|
+
`File: ${agent.file}`,
|
|
1670
|
+
`Model: ${agent.provider}/${agent.model}`,
|
|
1671
|
+
"Tools:",
|
|
1672
|
+
...renderList(agent.tools).split("\n"),
|
|
1673
|
+
`Stop when: ${JSON.stringify(agent.stopWhen)}`,
|
|
1674
|
+
"",
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
if (contract.ai.agents.length === 0) {
|
|
1678
|
+
lines.push("- none", "");
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1474
1681
|
lines.push("## Frontend", "");
|
|
1475
1682
|
lines.push(`Present: ${contract.frontend.present ? "yes" : "no"}`);
|
|
1476
1683
|
lines.push(`Framework: ${contract.frontend.framework}`);
|
|
@@ -1631,6 +1838,70 @@ function renderCapabilityMapMd(capabilityMap: AgentCapabilityMap): string {
|
|
|
1631
1838
|
return normalizeNewlines(lines.join("\n"));
|
|
1632
1839
|
}
|
|
1633
1840
|
|
|
1841
|
+
function renderAgentToolsMd(registry: AgentToolRegistry): string {
|
|
1842
|
+
const lines = [
|
|
1843
|
+
"# Agent Tools",
|
|
1844
|
+
"",
|
|
1845
|
+
`Project: ${registry.project.name}`,
|
|
1846
|
+
"",
|
|
1847
|
+
"## Explicit AI Tools",
|
|
1848
|
+
"",
|
|
1849
|
+
];
|
|
1850
|
+
|
|
1851
|
+
for (const tool of registry.explicitTools) {
|
|
1852
|
+
lines.push(
|
|
1853
|
+
`### ${tool.name}`,
|
|
1854
|
+
`File: ${tool.file}`,
|
|
1855
|
+
`Risk: ${tool.risk}`,
|
|
1856
|
+
`Strict: ${tool.strict ? "yes" : "no"}`,
|
|
1857
|
+
`Needs approval: ${String(tool.needsApproval)}`,
|
|
1858
|
+
`Description: ${tool.description ?? "none"}`,
|
|
1859
|
+
"",
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
if (registry.explicitTools.length === 0) {
|
|
1863
|
+
lines.push("- none", "");
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
lines.push("## Auto Tools From Forge Runtime", "");
|
|
1867
|
+
for (const tool of registry.autoTools) {
|
|
1868
|
+
lines.push(
|
|
1869
|
+
`### ${tool.name}`,
|
|
1870
|
+
`Source: ${tool.sourceKind} ${tool.sourceName}`,
|
|
1871
|
+
`File: ${tool.file}`,
|
|
1872
|
+
`HTTP: ${tool.http.method} ${tool.http.path}`,
|
|
1873
|
+
`Policy: ${tool.policy ?? "none"}`,
|
|
1874
|
+
`Requires auth: ${tool.requiresAuth ? "yes" : "no"}`,
|
|
1875
|
+
`Read-only: ${tool.readOnly ? "yes" : "no"}`,
|
|
1876
|
+
`Frontend hook: \`${tool.frontend.hook}\``,
|
|
1877
|
+
`Reads: ${tool.tablesRead.length > 0 ? tool.tablesRead.join(", ") : "none"}`,
|
|
1878
|
+
`Writes: ${tool.tablesWritten.length > 0 ? tool.tablesWritten.join(", ") : "none"}`,
|
|
1879
|
+
`Emits: ${tool.emits.length > 0 ? tool.emits.join(", ") : "none"}`,
|
|
1880
|
+
"",
|
|
1881
|
+
);
|
|
1882
|
+
}
|
|
1883
|
+
if (registry.autoTools.length === 0) {
|
|
1884
|
+
lines.push("- none", "");
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
lines.push("## Agents", "");
|
|
1888
|
+
for (const agent of registry.agents) {
|
|
1889
|
+
lines.push(
|
|
1890
|
+
`### ${agent.name}`,
|
|
1891
|
+
`File: ${agent.file}`,
|
|
1892
|
+
`Model: ${agent.provider}/${agent.model}`,
|
|
1893
|
+
`Tools: ${agent.tools.length > 0 ? agent.tools.join(", ") : "none"}`,
|
|
1894
|
+
`Stop when: ${JSON.stringify(agent.stopWhen)}`,
|
|
1895
|
+
"",
|
|
1896
|
+
);
|
|
1897
|
+
}
|
|
1898
|
+
if (registry.agents.length === 0) {
|
|
1899
|
+
lines.push("- none", "");
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
return normalizeNewlines(lines.join("\n"));
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1634
1905
|
function renderOperationPlaybooksMd(playbookEntries: AgentPlaybook[]): string {
|
|
1635
1906
|
const lines = ["# Operation Playbooks", ""];
|
|
1636
1907
|
for (const playbook of playbookEntries) {
|
|
@@ -1657,7 +1928,9 @@ forge dev
|
|
|
1657
1928
|
forge inspect all --json
|
|
1658
1929
|
forge inspect frontend --json
|
|
1659
1930
|
forge inspect capabilities --json
|
|
1931
|
+
forge inspect agent-tools --json
|
|
1660
1932
|
forge check --json
|
|
1933
|
+
forge ai trace <traceId> --json
|
|
1661
1934
|
\`\`\`
|
|
1662
1935
|
|
|
1663
1936
|
Never edit:
|
|
@@ -145,6 +145,23 @@ export interface AgentAiInfo {
|
|
|
145
145
|
file: string;
|
|
146
146
|
purpose?: string;
|
|
147
147
|
}>;
|
|
148
|
+
tools: Array<{
|
|
149
|
+
name: string;
|
|
150
|
+
file: string;
|
|
151
|
+
description?: string;
|
|
152
|
+
risk: string;
|
|
153
|
+
strict: boolean;
|
|
154
|
+
needsApproval: boolean | "dynamic";
|
|
155
|
+
}>;
|
|
156
|
+
agents: Array<{
|
|
157
|
+
name: string;
|
|
158
|
+
file: string;
|
|
159
|
+
provider: string;
|
|
160
|
+
model: string;
|
|
161
|
+
instructions?: string;
|
|
162
|
+
tools: string[];
|
|
163
|
+
stopWhen: unknown;
|
|
164
|
+
}>;
|
|
148
165
|
}
|
|
149
166
|
|
|
150
167
|
export interface AgentClientInfo {
|
|
@@ -306,6 +323,30 @@ export interface AgentCapabilityMap {
|
|
|
306
323
|
diagnostics: Diagnostic[];
|
|
307
324
|
}
|
|
308
325
|
|
|
326
|
+
export interface AgentToolRegistry {
|
|
327
|
+
schemaVersion: "0.1.0";
|
|
328
|
+
generatorVersion: string;
|
|
329
|
+
project: AgentProjectInfo;
|
|
330
|
+
explicitTools: AgentAiInfo["tools"];
|
|
331
|
+
autoTools: Array<{
|
|
332
|
+
name: string;
|
|
333
|
+
sourceKind: "command" | "query" | "liveQuery";
|
|
334
|
+
sourceName: string;
|
|
335
|
+
policy?: string;
|
|
336
|
+
file: string;
|
|
337
|
+
http: AgentHttpEndpointInfo;
|
|
338
|
+
frontend: AgentFrontendUsageInfo;
|
|
339
|
+
tablesRead: string[];
|
|
340
|
+
tablesWritten: string[];
|
|
341
|
+
emits: string[];
|
|
342
|
+
dependencies: Array<{ table: string; scope: "tenant" | "global" }>;
|
|
343
|
+
readOnly: boolean;
|
|
344
|
+
requiresAuth: boolean;
|
|
345
|
+
execution: "forge-runtime-endpoint";
|
|
346
|
+
}>;
|
|
347
|
+
agents: AgentAiInfo["agents"];
|
|
348
|
+
}
|
|
349
|
+
|
|
309
350
|
export interface AgentPlaybook {
|
|
310
351
|
title: string;
|
|
311
352
|
steps: string[];
|
|
@@ -4,9 +4,11 @@ import { canonicalJson } from "../primitives/serialize.ts";
|
|
|
4
4
|
import type { AppGraph } from "../types/app-graph.ts";
|
|
5
5
|
import type {
|
|
6
6
|
AiGenerationCall,
|
|
7
|
+
AiAgentDefinition,
|
|
7
8
|
AiModelDefinition,
|
|
8
9
|
AiProviderDefinition,
|
|
9
10
|
AiRegistry,
|
|
11
|
+
AiToolDefinition,
|
|
10
12
|
ForgeAiProvider,
|
|
11
13
|
} from "../types/ai-registry.ts";
|
|
12
14
|
import type { ClassifiedPackage } from "../classifier/runtime-matrix.ts";
|
|
@@ -15,9 +17,17 @@ import {
|
|
|
15
17
|
AI_REGISTRY_ANALYZER_VERSION,
|
|
16
18
|
AI_REGISTRY_SCHEMA_VERSION,
|
|
17
19
|
} from "./constants.ts";
|
|
18
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
parseAiAgentMeta,
|
|
22
|
+
parseAiCallsFromSlice,
|
|
23
|
+
parseAiToolMeta,
|
|
24
|
+
} from "./parse.ts";
|
|
19
25
|
|
|
20
26
|
const KNOWN_MODELS: AiModelDefinition[] = [
|
|
27
|
+
{
|
|
28
|
+
provider: "openai",
|
|
29
|
+
model: "gpt-5.4",
|
|
30
|
+
},
|
|
21
31
|
{
|
|
22
32
|
provider: "openai",
|
|
23
33
|
model: "gpt-4o",
|
|
@@ -30,6 +40,10 @@ const KNOWN_MODELS: AiModelDefinition[] = [
|
|
|
30
40
|
inputCostPer1kTokensUsd: 0.00015,
|
|
31
41
|
outputCostPer1kTokensUsd: 0.0006,
|
|
32
42
|
},
|
|
43
|
+
{
|
|
44
|
+
provider: "anthropic",
|
|
45
|
+
model: "claude-sonnet-4.5",
|
|
46
|
+
},
|
|
33
47
|
{
|
|
34
48
|
provider: "anthropic",
|
|
35
49
|
model: "claude-3-5-sonnet-20241022",
|
|
@@ -42,6 +56,14 @@ const KNOWN_MODELS: AiModelDefinition[] = [
|
|
|
42
56
|
inputCostPer1kTokensUsd: 0.0008,
|
|
43
57
|
outputCostPer1kTokensUsd: 0.004,
|
|
44
58
|
},
|
|
59
|
+
{
|
|
60
|
+
provider: "gateway",
|
|
61
|
+
model: "openai/gpt-5.4",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
provider: "gateway",
|
|
65
|
+
model: "anthropic/claude-sonnet-4.5",
|
|
66
|
+
},
|
|
45
67
|
{
|
|
46
68
|
provider: "gateway",
|
|
47
69
|
model: "openai/gpt-4o",
|
|
@@ -123,12 +145,39 @@ export function buildAiRegistry(
|
|
|
123
145
|
classified: ClassifiedPackage[],
|
|
124
146
|
): AiRegistry {
|
|
125
147
|
const generations: AiGenerationCall[] = [];
|
|
148
|
+
const tools: AiToolDefinition[] = [];
|
|
149
|
+
const agents: AiAgentDefinition[] = [];
|
|
126
150
|
|
|
127
151
|
for (const symbol of appGraph.symbols) {
|
|
128
152
|
const sourceSlice =
|
|
129
153
|
typeof symbol.meta.sourceSlice === "string" ? symbol.meta.sourceSlice : "";
|
|
130
154
|
if (sourceSlice.length === 0) continue;
|
|
131
155
|
|
|
156
|
+
if (symbol.kind === "aiTool") {
|
|
157
|
+
const meta = parseAiToolMeta(sourceSlice);
|
|
158
|
+
tools.push({
|
|
159
|
+
name: symbol.name,
|
|
160
|
+
file: symbol.file,
|
|
161
|
+
...(meta.description ? { description: meta.description } : {}),
|
|
162
|
+
risk: meta.risk,
|
|
163
|
+
strict: meta.strict,
|
|
164
|
+
needsApproval: meta.needsApproval,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (symbol.kind === "agent") {
|
|
169
|
+
const meta = parseAiAgentMeta(sourceSlice);
|
|
170
|
+
agents.push({
|
|
171
|
+
name: symbol.name,
|
|
172
|
+
file: symbol.file,
|
|
173
|
+
provider: meta.provider ?? "gateway",
|
|
174
|
+
model: meta.model ?? "unknown",
|
|
175
|
+
...(meta.instructions ? { instructions: meta.instructions } : {}),
|
|
176
|
+
tools: meta.tools,
|
|
177
|
+
stopWhen: meta.stopWhen,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
132
181
|
for (const call of parseAiCallsFromSlice(sourceSlice)) {
|
|
133
182
|
generations.push({
|
|
134
183
|
provider: call.provider ?? "openai",
|
|
@@ -145,6 +194,16 @@ export function buildAiRegistry(
|
|
|
145
194
|
if (fileCmp !== 0) return fileCmp;
|
|
146
195
|
return a.method.localeCompare(b.method);
|
|
147
196
|
});
|
|
197
|
+
tools.sort((a, b) => {
|
|
198
|
+
const nameCmp = a.name.localeCompare(b.name);
|
|
199
|
+
if (nameCmp !== 0) return nameCmp;
|
|
200
|
+
return a.file.localeCompare(b.file);
|
|
201
|
+
});
|
|
202
|
+
agents.sort((a, b) => {
|
|
203
|
+
const nameCmp = a.name.localeCompare(b.name);
|
|
204
|
+
if (nameCmp !== 0) return nameCmp;
|
|
205
|
+
return a.file.localeCompare(b.file);
|
|
206
|
+
});
|
|
148
207
|
|
|
149
208
|
return {
|
|
150
209
|
schemaVersion: AI_REGISTRY_SCHEMA_VERSION,
|
|
@@ -158,6 +217,8 @@ export function buildAiRegistry(
|
|
|
158
217
|
),
|
|
159
218
|
providers: buildProviders(classified),
|
|
160
219
|
generations,
|
|
220
|
+
tools,
|
|
221
|
+
agents,
|
|
161
222
|
diagnostics: [],
|
|
162
223
|
};
|
|
163
224
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const AI_REGISTRY_SCHEMA_VERSION = "1";
|
|
2
|
-
export const AI_REGISTRY_ANALYZER_VERSION = "1.
|
|
2
|
+
export const AI_REGISTRY_ANALYZER_VERSION = "1.1.0";
|