forgeos 0.1.0-alpha.2 → 0.1.0-alpha.4
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/CHANGELOG.md +29 -0
- package/README.md +25 -10
- package/package.json +8 -5
- 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 +512 -260
- 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 +339 -17
- 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 +351 -1
- package/src/forge/cli/auth.ts +36 -1
- package/src/forge/cli/commands.ts +19 -0
- package/src/forge/cli/parse.ts +67 -8
- package/src/forge/cli/rls.ts +529 -17
- package/src/forge/cli/secrets.ts +46 -1
- package/src/forge/cli/security.ts +269 -0
- package/src/forge/compiler/agent-contract/build.ts +289 -8
- package/src/forge/compiler/agent-contract/types.ts +43 -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/diagnostics/codes.ts +15 -0
- package/src/forge/compiler/diagnostics/create.ts +1 -1
- 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/package-graph/compiler.ts +13 -3
- 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/auth/claims.ts +32 -0
- package/src/forge/runtime/auth/errors.ts +2 -0
- package/src/forge/runtime/context/create-context.ts +30 -6
- package/src/forge/runtime/db/memory-adapter.ts +2 -2
- package/src/forge/runtime/telemetry/scrubber.ts +56 -5
- package/src/forge/runtime/webhooks/security.ts +184 -0
- package/src/forge/server.ts +93 -0
- package/src/forge/version.ts +1 -1
- package/templates/b2b-support-web/package.json +1 -0
- package/templates/b2b-support-web/tsconfig.json +4 -1
- package/templates/minimal-web/package.json +1 -0
- package/templates/minimal-web/tsconfig.json +3 -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,78 @@ 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
|
+
risk: "write" as const,
|
|
706
|
+
needsApproval: true,
|
|
707
|
+
requiresAuth: command.policy !== undefined && command.policy !== "public",
|
|
708
|
+
execution: "forge-runtime-endpoint" as const,
|
|
709
|
+
})),
|
|
710
|
+
...contract.queries.map((query) => ({
|
|
711
|
+
name: autoToolName("query", query.name),
|
|
712
|
+
sourceKind: "query" as const,
|
|
713
|
+
sourceName: query.name,
|
|
714
|
+
...(query.policy ? { policy: query.policy } : {}),
|
|
715
|
+
file: query.file,
|
|
716
|
+
http: query.http,
|
|
717
|
+
frontend: query.frontend,
|
|
718
|
+
tablesRead: query.tablesRead,
|
|
719
|
+
tablesWritten: [],
|
|
720
|
+
emits: [],
|
|
721
|
+
dependencies: [],
|
|
722
|
+
readOnly: true,
|
|
723
|
+
risk: "read" as const,
|
|
724
|
+
needsApproval: false,
|
|
725
|
+
requiresAuth: query.policy !== undefined && query.policy !== "public",
|
|
726
|
+
execution: "forge-runtime-endpoint" as const,
|
|
727
|
+
})),
|
|
728
|
+
...contract.liveQueries.map((liveQuery) => ({
|
|
729
|
+
name: autoToolName("liveQuery", liveQuery.name),
|
|
730
|
+
sourceKind: "liveQuery" as const,
|
|
731
|
+
sourceName: liveQuery.name,
|
|
732
|
+
...(liveQuery.policy ? { policy: liveQuery.policy } : {}),
|
|
733
|
+
file: liveQuery.file,
|
|
734
|
+
http: liveQuery.http,
|
|
735
|
+
frontend: liveQuery.frontend,
|
|
736
|
+
tablesRead: liveQuery.tablesRead,
|
|
737
|
+
tablesWritten: [],
|
|
738
|
+
emits: [],
|
|
739
|
+
dependencies: liveQuery.dependencies,
|
|
740
|
+
readOnly: true,
|
|
741
|
+
risk: "read" as const,
|
|
742
|
+
needsApproval: false,
|
|
743
|
+
requiresAuth: liveQuery.policy !== undefined && liveQuery.policy !== "public",
|
|
744
|
+
execution: "forge-runtime-endpoint" as const,
|
|
745
|
+
})),
|
|
746
|
+
].sort((a, b) => a.name.localeCompare(b.name));
|
|
747
|
+
|
|
748
|
+
return {
|
|
749
|
+
schemaVersion: "0.1.0",
|
|
750
|
+
generatorVersion: GENERATOR_VERSION,
|
|
751
|
+
project: contract.project,
|
|
752
|
+
explicitTools: contract.ai.tools,
|
|
753
|
+
autoTools,
|
|
754
|
+
agents: contract.ai.agents,
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
|
|
659
758
|
function jsAccess(group: string, name: string): string {
|
|
660
759
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name)
|
|
661
760
|
? `api.${group}.${name}`
|
|
@@ -951,6 +1050,23 @@ export function buildAgentContractArtifacts(
|
|
|
951
1050
|
...(generation.purpose ? { purpose: generation.purpose } : {}),
|
|
952
1051
|
}))
|
|
953
1052
|
.sort((a, b) => `${a.file}:${a.method}:${a.model}`.localeCompare(`${b.file}:${b.method}:${b.model}`)),
|
|
1053
|
+
tools: input.aiRegistry.tools.map((tool) => ({
|
|
1054
|
+
name: tool.name,
|
|
1055
|
+
file: tool.file,
|
|
1056
|
+
...(tool.description ? { description: tool.description } : {}),
|
|
1057
|
+
risk: tool.risk,
|
|
1058
|
+
strict: tool.strict,
|
|
1059
|
+
needsApproval: tool.needsApproval,
|
|
1060
|
+
})),
|
|
1061
|
+
agents: input.aiRegistry.agents.map((agent) => ({
|
|
1062
|
+
name: agent.name,
|
|
1063
|
+
file: agent.file,
|
|
1064
|
+
provider: agent.provider,
|
|
1065
|
+
model: agent.model,
|
|
1066
|
+
...(agent.instructions ? { instructions: agent.instructions } : {}),
|
|
1067
|
+
tools: agent.tools,
|
|
1068
|
+
stopWhen: agent.stopWhen,
|
|
1069
|
+
})),
|
|
954
1070
|
},
|
|
955
1071
|
client: {
|
|
956
1072
|
queries: input.clientManifest.queries,
|
|
@@ -1038,14 +1154,17 @@ export function buildAgentContractArtifacts(
|
|
|
1038
1154
|
: null;
|
|
1039
1155
|
const userNotes = extractUserNotes(existingAgents);
|
|
1040
1156
|
const agentsMd = renderAgentsMd(contract, userNotes);
|
|
1157
|
+
const toolRegistry = buildAgentToolRegistry(contract);
|
|
1041
1158
|
const capabilityMap = buildCapabilityMap(contract);
|
|
1042
1159
|
const capabilityMapMd = renderCapabilityMapMd(capabilityMap);
|
|
1160
|
+
const agentToolsMd = renderAgentToolsMd(toolRegistry);
|
|
1043
1161
|
const appMapMd = renderAppMapMd(contract);
|
|
1044
1162
|
const runtimeRulesMd = renderRuntimeRulesMd(contract.rules);
|
|
1045
1163
|
const operationPlaybooksMd = renderOperationPlaybooksMd(contract.playbooks);
|
|
1046
1164
|
const agentQuickstartMd = renderAgentQuickstartMd();
|
|
1047
1165
|
const diagnostics = scanAgentContractForLeaks(contract, [
|
|
1048
1166
|
agentsMd,
|
|
1167
|
+
agentToolsMd,
|
|
1049
1168
|
capabilityMapMd,
|
|
1050
1169
|
appMapMd,
|
|
1051
1170
|
runtimeRulesMd,
|
|
@@ -1056,9 +1175,11 @@ export function buildAgentContractArtifacts(
|
|
|
1056
1175
|
return {
|
|
1057
1176
|
contract,
|
|
1058
1177
|
capabilityMap,
|
|
1178
|
+
toolRegistry,
|
|
1059
1179
|
agentsMd,
|
|
1060
1180
|
appMapMd,
|
|
1061
1181
|
capabilityMapMd,
|
|
1182
|
+
agentToolsMd,
|
|
1062
1183
|
runtimeRulesMd,
|
|
1063
1184
|
operationPlaybooksMd,
|
|
1064
1185
|
agentQuickstartMd,
|
|
@@ -1099,6 +1220,15 @@ export function serializeCapabilityMapTs(capabilityMap: AgentCapabilityMap): str
|
|
|
1099
1220
|
return `export const capabilityMap = ${JSON.stringify(parsed, null, 2)} as const;\n`;
|
|
1100
1221
|
}
|
|
1101
1222
|
|
|
1223
|
+
export function serializeAgentToolRegistryJson(registry: AgentToolRegistry): string {
|
|
1224
|
+
return serializeCanonical(registry);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
export function serializeAgentToolRegistryTs(registry: AgentToolRegistry): string {
|
|
1228
|
+
const parsed = JSON.parse(serializeAgentToolRegistryJson(registry)) as unknown;
|
|
1229
|
+
return `export const agentTools = ${JSON.stringify(parsed, null, 2)} as const;\n`;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1102
1232
|
function renderAgentsMd(contract: AgentContract, userNotes: string): string {
|
|
1103
1233
|
const tenantTables = contract.data.tables
|
|
1104
1234
|
.filter((table) => table.tenantScoped)
|
|
@@ -1107,6 +1237,12 @@ function renderAgentsMd(contract: AgentContract, userNotes: string): string {
|
|
|
1107
1237
|
`${policy.name}: ${policy.roles.length > 0 ? policy.roles.join(", ") : policy.kind}`,
|
|
1108
1238
|
);
|
|
1109
1239
|
const secrets = contract.secrets.map((secret) => `${secret.name}${secret.required ? " (required)" : " (optional)"}`);
|
|
1240
|
+
const aiTools = contract.ai.tools.map((tool) =>
|
|
1241
|
+
`${tool.name}: ${tool.description ?? "no description"} (${tool.risk}${tool.needsApproval ? ", approval" : ""})`,
|
|
1242
|
+
);
|
|
1243
|
+
const aiAgents = contract.ai.agents.map((agent) =>
|
|
1244
|
+
`${agent.name}: ${agent.provider}/${agent.model} with ${agent.tools.length > 0 ? agent.tools.join(", ") : "no tools"}`,
|
|
1245
|
+
);
|
|
1110
1246
|
|
|
1111
1247
|
return normalizeNewlines(`# AGENTS.md
|
|
1112
1248
|
|
|
@@ -1178,6 +1314,7 @@ forge inspect app --json
|
|
|
1178
1314
|
forge inspect all --json
|
|
1179
1315
|
forge inspect frontend --json
|
|
1180
1316
|
forge inspect capabilities --json
|
|
1317
|
+
forge inspect agent-tools --json
|
|
1181
1318
|
forge deps inspect <package> --json
|
|
1182
1319
|
forge deps api <package> <symbol> --json
|
|
1183
1320
|
forge deps trace <package> --json
|
|
@@ -1191,6 +1328,9 @@ forge doctor
|
|
|
1191
1328
|
forge doctor windows --json
|
|
1192
1329
|
forge setup windows --json
|
|
1193
1330
|
forge agent print-context --json
|
|
1331
|
+
forge ai tools --json
|
|
1332
|
+
forge ai agents --json
|
|
1333
|
+
forge ai trace <traceId> --json
|
|
1194
1334
|
forge verify --smoke
|
|
1195
1335
|
forge verify --standard
|
|
1196
1336
|
forge verify --strict
|
|
@@ -1210,6 +1350,21 @@ ${renderList(policies)}
|
|
|
1210
1350
|
|
|
1211
1351
|
${renderList(secrets)}
|
|
1212
1352
|
|
|
1353
|
+
## AI Tools And Agents
|
|
1354
|
+
|
|
1355
|
+
- AI SDK engine: Vercel AI SDK v6.
|
|
1356
|
+
- Forge layer: generated registry, runtime rules, telemetry, secrets, tenant/auth context, and agent contract.
|
|
1357
|
+
- Use \`ctx.agent.run\` or \`ctx.ai.runAgent\` only in actions, workflows, endpoints, and server code.
|
|
1358
|
+
- Do not create custom tool loops; use Forge tools and AI SDK \`ToolLoopAgent\` through the Forge runtime.
|
|
1359
|
+
|
|
1360
|
+
Tools:
|
|
1361
|
+
|
|
1362
|
+
${renderList(aiTools)}
|
|
1363
|
+
|
|
1364
|
+
Agents:
|
|
1365
|
+
|
|
1366
|
+
${renderList(aiAgents)}
|
|
1367
|
+
|
|
1213
1368
|
## Auth
|
|
1214
1369
|
|
|
1215
1370
|
- Modes: ${contract.auth.modes.join(", ")}
|
|
@@ -1268,6 +1423,7 @@ Use:
|
|
|
1268
1423
|
forge make resource <name> --fields title:text,status:enum(open,closed) --dry-run --json
|
|
1269
1424
|
forge make resource <name> --fields title:text,status:enum(open,closed) --with-ui --yes
|
|
1270
1425
|
forge make ui --framework vite --dry-run --json
|
|
1426
|
+
forge make ai-chat support --dry-run --json
|
|
1271
1427
|
\`\`\`
|
|
1272
1428
|
|
|
1273
1429
|
Review the plan before applying when the resource touches schema or policies.
|
|
@@ -1304,11 +1460,13 @@ Use:
|
|
|
1304
1460
|
\`\`\`bash
|
|
1305
1461
|
forge refactor rename field tickets.priority tickets.urgency --dry-run --json
|
|
1306
1462
|
forge refactor rename field tickets.priority tickets.urgency --yes
|
|
1463
|
+
forge refactor rename command createTicket openTicket --dry-run --json
|
|
1464
|
+
forge refactor rename command createTicket openTicket --yes
|
|
1307
1465
|
\`\`\`
|
|
1308
1466
|
|
|
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\`.
|
|
1467
|
+
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
1468
|
|
|
1311
|
-
Never edit \`src/forge/_generated/**\` directly. Review migration hints before applying field or table renames.
|
|
1469
|
+
Never edit \`src/forge/_generated/**\` directly. Review migration hints before applying command, field, or table renames.
|
|
1312
1470
|
|
|
1313
1471
|
### Plan impact-based tests
|
|
1314
1472
|
|
|
@@ -1334,6 +1492,19 @@ forge repair plan --from-last-test-run --write
|
|
|
1334
1492
|
|
|
1335
1493
|
Apply only high-confidence deterministic repairs automatically. Review medium or low confidence repairs before changing code.
|
|
1336
1494
|
|
|
1495
|
+
### Add AI tools or agents
|
|
1496
|
+
|
|
1497
|
+
Use:
|
|
1498
|
+
|
|
1499
|
+
\`\`\`bash
|
|
1500
|
+
forge generate
|
|
1501
|
+
forge inspect all --json
|
|
1502
|
+
forge ai check --json
|
|
1503
|
+
forge ai trace <traceId> --json
|
|
1504
|
+
\`\`\`
|
|
1505
|
+
|
|
1506
|
+
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\`.
|
|
1507
|
+
|
|
1337
1508
|
### Export agent adapters
|
|
1338
1509
|
|
|
1339
1510
|
Use:
|
|
@@ -1471,6 +1642,48 @@ function renderAppMapMd(contract: AgentContract): string {
|
|
|
1471
1642
|
lines.push(`### ${workflow.name}`, `Trigger: ${workflow.trigger ?? "manual"}`, "Steps:", ...renderList(workflow.steps).split("\n"), "");
|
|
1472
1643
|
}
|
|
1473
1644
|
|
|
1645
|
+
lines.push("## AI", "");
|
|
1646
|
+
lines.push("### Providers", "", ...renderList(contract.ai.providers).split("\n"), "");
|
|
1647
|
+
lines.push("### Generations", "");
|
|
1648
|
+
for (const generation of contract.ai.generations) {
|
|
1649
|
+
lines.push(
|
|
1650
|
+
`- ${generation.method}: ${generation.provider}/${generation.model} in ${generation.file}${generation.purpose ? ` (${generation.purpose})` : ""}`,
|
|
1651
|
+
);
|
|
1652
|
+
}
|
|
1653
|
+
if (contract.ai.generations.length === 0) {
|
|
1654
|
+
lines.push("- none");
|
|
1655
|
+
}
|
|
1656
|
+
lines.push("", "### Tools", "");
|
|
1657
|
+
for (const tool of contract.ai.tools) {
|
|
1658
|
+
lines.push(
|
|
1659
|
+
`#### ${tool.name}`,
|
|
1660
|
+
`File: ${tool.file}`,
|
|
1661
|
+
`Risk: ${tool.risk}`,
|
|
1662
|
+
`Strict: ${tool.strict ? "yes" : "no"}`,
|
|
1663
|
+
`Needs approval: ${String(tool.needsApproval)}`,
|
|
1664
|
+
`Description: ${tool.description ?? "none"}`,
|
|
1665
|
+
"",
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1668
|
+
if (contract.ai.tools.length === 0) {
|
|
1669
|
+
lines.push("- none", "");
|
|
1670
|
+
}
|
|
1671
|
+
lines.push("### Agents", "");
|
|
1672
|
+
for (const agent of contract.ai.agents) {
|
|
1673
|
+
lines.push(
|
|
1674
|
+
`#### ${agent.name}`,
|
|
1675
|
+
`File: ${agent.file}`,
|
|
1676
|
+
`Model: ${agent.provider}/${agent.model}`,
|
|
1677
|
+
"Tools:",
|
|
1678
|
+
...renderList(agent.tools).split("\n"),
|
|
1679
|
+
`Stop when: ${JSON.stringify(agent.stopWhen)}`,
|
|
1680
|
+
"",
|
|
1681
|
+
);
|
|
1682
|
+
}
|
|
1683
|
+
if (contract.ai.agents.length === 0) {
|
|
1684
|
+
lines.push("- none", "");
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1474
1687
|
lines.push("## Frontend", "");
|
|
1475
1688
|
lines.push(`Present: ${contract.frontend.present ? "yes" : "no"}`);
|
|
1476
1689
|
lines.push(`Framework: ${contract.frontend.framework}`);
|
|
@@ -1631,6 +1844,72 @@ function renderCapabilityMapMd(capabilityMap: AgentCapabilityMap): string {
|
|
|
1631
1844
|
return normalizeNewlines(lines.join("\n"));
|
|
1632
1845
|
}
|
|
1633
1846
|
|
|
1847
|
+
function renderAgentToolsMd(registry: AgentToolRegistry): string {
|
|
1848
|
+
const lines = [
|
|
1849
|
+
"# Agent Tools",
|
|
1850
|
+
"",
|
|
1851
|
+
`Project: ${registry.project.name}`,
|
|
1852
|
+
"",
|
|
1853
|
+
"## Explicit AI Tools",
|
|
1854
|
+
"",
|
|
1855
|
+
];
|
|
1856
|
+
|
|
1857
|
+
for (const tool of registry.explicitTools) {
|
|
1858
|
+
lines.push(
|
|
1859
|
+
`### ${tool.name}`,
|
|
1860
|
+
`File: ${tool.file}`,
|
|
1861
|
+
`Risk: ${tool.risk}`,
|
|
1862
|
+
`Strict: ${tool.strict ? "yes" : "no"}`,
|
|
1863
|
+
`Needs approval: ${String(tool.needsApproval)}`,
|
|
1864
|
+
`Description: ${tool.description ?? "none"}`,
|
|
1865
|
+
"",
|
|
1866
|
+
);
|
|
1867
|
+
}
|
|
1868
|
+
if (registry.explicitTools.length === 0) {
|
|
1869
|
+
lines.push("- none", "");
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
lines.push("## Auto Tools From Forge Runtime", "");
|
|
1873
|
+
for (const tool of registry.autoTools) {
|
|
1874
|
+
lines.push(
|
|
1875
|
+
`### ${tool.name}`,
|
|
1876
|
+
`Source: ${tool.sourceKind} ${tool.sourceName}`,
|
|
1877
|
+
`File: ${tool.file}`,
|
|
1878
|
+
`HTTP: ${tool.http.method} ${tool.http.path}`,
|
|
1879
|
+
`Policy: ${tool.policy ?? "none"}`,
|
|
1880
|
+
`Requires auth: ${tool.requiresAuth ? "yes" : "no"}`,
|
|
1881
|
+
`Read-only: ${tool.readOnly ? "yes" : "no"}`,
|
|
1882
|
+
`Risk: ${tool.risk}`,
|
|
1883
|
+
`Needs approval: ${String(tool.needsApproval)}`,
|
|
1884
|
+
`Frontend hook: \`${tool.frontend.hook}\``,
|
|
1885
|
+
`Reads: ${tool.tablesRead.length > 0 ? tool.tablesRead.join(", ") : "none"}`,
|
|
1886
|
+
`Writes: ${tool.tablesWritten.length > 0 ? tool.tablesWritten.join(", ") : "none"}`,
|
|
1887
|
+
`Emits: ${tool.emits.length > 0 ? tool.emits.join(", ") : "none"}`,
|
|
1888
|
+
"",
|
|
1889
|
+
);
|
|
1890
|
+
}
|
|
1891
|
+
if (registry.autoTools.length === 0) {
|
|
1892
|
+
lines.push("- none", "");
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
lines.push("## Agents", "");
|
|
1896
|
+
for (const agent of registry.agents) {
|
|
1897
|
+
lines.push(
|
|
1898
|
+
`### ${agent.name}`,
|
|
1899
|
+
`File: ${agent.file}`,
|
|
1900
|
+
`Model: ${agent.provider}/${agent.model}`,
|
|
1901
|
+
`Tools: ${agent.tools.length > 0 ? agent.tools.join(", ") : "none"}`,
|
|
1902
|
+
`Stop when: ${JSON.stringify(agent.stopWhen)}`,
|
|
1903
|
+
"",
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
if (registry.agents.length === 0) {
|
|
1907
|
+
lines.push("- none", "");
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
return normalizeNewlines(lines.join("\n"));
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1634
1913
|
function renderOperationPlaybooksMd(playbookEntries: AgentPlaybook[]): string {
|
|
1635
1914
|
const lines = ["# Operation Playbooks", ""];
|
|
1636
1915
|
for (const playbook of playbookEntries) {
|
|
@@ -1657,7 +1936,9 @@ forge dev
|
|
|
1657
1936
|
forge inspect all --json
|
|
1658
1937
|
forge inspect frontend --json
|
|
1659
1938
|
forge inspect capabilities --json
|
|
1939
|
+
forge inspect agent-tools --json
|
|
1660
1940
|
forge check --json
|
|
1941
|
+
forge ai trace <traceId> --json
|
|
1661
1942
|
\`\`\`
|
|
1662
1943
|
|
|
1663
1944
|
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,32 @@ 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
|
+
risk: "read" | "write";
|
|
345
|
+
needsApproval: boolean;
|
|
346
|
+
requiresAuth: boolean;
|
|
347
|
+
execution: "forge-runtime-endpoint";
|
|
348
|
+
}>;
|
|
349
|
+
agents: AgentAiInfo["agents"];
|
|
350
|
+
}
|
|
351
|
+
|
|
309
352
|
export interface AgentPlaybook {
|
|
310
353
|
title: string;
|
|
311
354
|
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";
|