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.
Files changed (163) hide show
  1. package/AGENTS.md +38 -3
  2. package/README.md +6 -5
  3. package/package.json +5 -4
  4. package/src/forge/_generated/actionSubscriptions.json +2 -2
  5. package/src/forge/_generated/actionSubscriptions.ts +3 -3
  6. package/src/forge/_generated/agentAdapterManifest.json +2 -2
  7. package/src/forge/_generated/agentAdapterManifest.ts +3 -3
  8. package/src/forge/_generated/agentContract.json +2 -2
  9. package/src/forge/_generated/agentContract.ts +183 -50
  10. package/src/forge/_generated/agentQuickstart.md +3 -1
  11. package/src/forge/_generated/agentTools.json +2 -0
  12. package/src/forge/_generated/agentTools.md +16 -0
  13. package/src/forge/_generated/agentTools.ts +12 -0
  14. package/src/forge/_generated/aiContext.ts +67 -1
  15. package/src/forge/_generated/aiModels.json +2 -2
  16. package/src/forge/_generated/aiModels.ts +17 -1
  17. package/src/forge/_generated/aiProviders.json +1 -1
  18. package/src/forge/_generated/aiProviders.ts +1 -1
  19. package/src/forge/_generated/aiRegistry.json +2 -2
  20. package/src/forge/_generated/aiRegistry.ts +7 -5
  21. package/src/forge/_generated/api.json +2 -2
  22. package/src/forge/_generated/api.ts +1 -1
  23. package/src/forge/_generated/appGraph.json +2 -2
  24. package/src/forge/_generated/appGraph.ts +288 -180
  25. package/src/forge/_generated/appMap.md +21 -1
  26. package/src/forge/_generated/artifactManifest.json +2 -2
  27. package/src/forge/_generated/artifactManifest.ts +2 -2
  28. package/src/forge/_generated/authClaims.json +1 -1
  29. package/src/forge/_generated/authClaims.ts +1 -1
  30. package/src/forge/_generated/authConfig.json +1 -1
  31. package/src/forge/_generated/authConfig.ts +1 -1
  32. package/src/forge/_generated/authContext.ts +1 -1
  33. package/src/forge/_generated/authRegistry.json +1 -1
  34. package/src/forge/_generated/authRegistry.ts +1 -1
  35. package/src/forge/_generated/buildInfo.json +2 -2
  36. package/src/forge/_generated/buildInfo.ts +4 -4
  37. package/src/forge/_generated/capabilityMap.json +2 -2
  38. package/src/forge/_generated/capabilityMap.md +1 -1
  39. package/src/forge/_generated/capabilityMap.ts +2 -2
  40. package/src/forge/_generated/client.ts +1 -1
  41. package/src/forge/_generated/clientApi.ts +1 -1
  42. package/src/forge/_generated/clientManifest.json +2 -2
  43. package/src/forge/_generated/clientManifest.ts +3 -3
  44. package/src/forge/_generated/clientTypes.ts +1 -1
  45. package/src/forge/_generated/configRegistry.json +1 -1
  46. package/src/forge/_generated/configRegistry.ts +1 -1
  47. package/src/forge/_generated/dataGraph.json +2 -2
  48. package/src/forge/_generated/dataGraph.ts +3 -3
  49. package/src/forge/_generated/db.json +1 -1
  50. package/src/forge/_generated/db.ts +1 -1
  51. package/src/forge/_generated/dbSecurityManifest.json +1 -1
  52. package/src/forge/_generated/dbSecurityManifest.ts +1 -1
  53. package/src/forge/_generated/dbSessionContext.json +1 -1
  54. package/src/forge/_generated/dbSessionContext.ts +1 -1
  55. package/src/forge/_generated/deployManifest.json +2 -2
  56. package/src/forge/_generated/deployManifest.ts +7 -7
  57. package/src/forge/_generated/devManifest.json +2 -2
  58. package/src/forge/_generated/devManifest.ts +18 -3
  59. package/src/forge/_generated/envSchema.json +1 -1
  60. package/src/forge/_generated/envSchema.ts +1 -1
  61. package/src/forge/_generated/frontendGraph.json +1 -1
  62. package/src/forge/_generated/frontendGraph.ts +1 -1
  63. package/src/forge/_generated/importGuards.json +1 -1
  64. package/src/forge/_generated/importGuards.ts +1 -1
  65. package/src/forge/_generated/index.ts +2 -1
  66. package/src/forge/_generated/liveProductionManifest.json +1 -1
  67. package/src/forge/_generated/liveProductionManifest.ts +1 -1
  68. package/src/forge/_generated/liveProtocol.json +1 -1
  69. package/src/forge/_generated/liveProtocol.ts +1 -1
  70. package/src/forge/_generated/liveQueryRegistry.json +2 -2
  71. package/src/forge/_generated/liveQueryRegistry.ts +3 -3
  72. package/src/forge/_generated/liveTransportConfig.json +1 -1
  73. package/src/forge/_generated/liveTransportConfig.ts +1 -1
  74. package/src/forge/_generated/makeRegistry.json +2 -2
  75. package/src/forge/_generated/makeRegistry.ts +16 -2
  76. package/src/forge/_generated/makeTemplates.json +2 -2
  77. package/src/forge/_generated/makeTemplates.ts +6 -1
  78. package/src/forge/_generated/mockMap.json +1 -1
  79. package/src/forge/_generated/mockMap.ts +1 -1
  80. package/src/forge/_generated/operationPlaybooks.md +34 -14
  81. package/src/forge/_generated/packageGraph.json +2 -2
  82. package/src/forge/_generated/packageGraph.ts +8808 -4723
  83. package/src/forge/_generated/packageUpgradeRegistry.json +2 -2
  84. package/src/forge/_generated/packageUpgradeRegistry.ts +2 -2
  85. package/src/forge/_generated/permissionMatrix.json +2 -2
  86. package/src/forge/_generated/permissionMatrix.ts +3 -3
  87. package/src/forge/_generated/policyRegistry.json +2 -2
  88. package/src/forge/_generated/policyRegistry.ts +3 -3
  89. package/src/forge/_generated/queryRegistry.json +2 -2
  90. package/src/forge/_generated/queryRegistry.ts +3 -3
  91. package/src/forge/_generated/react.d.ts +1 -1
  92. package/src/forge/_generated/react.ts +1 -1
  93. package/src/forge/_generated/reactManifest.json +2 -2
  94. package/src/forge/_generated/reactManifest.ts +3 -3
  95. package/src/forge/_generated/releaseManifest.json +2 -2
  96. package/src/forge/_generated/releaseManifest.ts +3 -3
  97. package/src/forge/_generated/rlsPolicies.json +1 -1
  98. package/src/forge/_generated/rlsPolicies.sql +1 -1
  99. package/src/forge/_generated/rlsPolicies.ts +1 -1
  100. package/src/forge/_generated/runtimeGraph.json +2 -2
  101. package/src/forge/_generated/runtimeGraph.ts +3 -3
  102. package/src/forge/_generated/runtimeMatrix.json +2 -2
  103. package/src/forge/_generated/runtimeMatrix.ts +8684 -1939
  104. package/src/forge/_generated/runtimeRegistry.ts +1 -1
  105. package/src/forge/_generated/runtimeRules.md +13 -1
  106. package/src/forge/_generated/secretRegistry.json +1 -1
  107. package/src/forge/_generated/secretRegistry.ts +1 -1
  108. package/src/forge/_generated/secretsContext.ts +1 -1
  109. package/src/forge/_generated/serverApi.ts +1 -1
  110. package/src/forge/_generated/sourceMapManifest.json +2 -2
  111. package/src/forge/_generated/sourceMapManifest.ts +2 -2
  112. package/src/forge/_generated/sqlPlan.json +1 -1
  113. package/src/forge/_generated/sqlPlan.ts +1 -1
  114. package/src/forge/_generated/subscriptionManifest.json +2 -2
  115. package/src/forge/_generated/subscriptionManifest.ts +3 -3
  116. package/src/forge/_generated/symbolicationManifest.json +2 -2
  117. package/src/forge/_generated/symbolicationManifest.ts +2 -2
  118. package/src/forge/_generated/telemetryRegistry.json +2 -2
  119. package/src/forge/_generated/telemetryRegistry.ts +3 -3
  120. package/src/forge/_generated/telemetrySinks.json +2 -2
  121. package/src/forge/_generated/telemetrySinks.ts +2 -2
  122. package/src/forge/_generated/tenantScope.json +2 -2
  123. package/src/forge/_generated/tenantScope.ts +3 -3
  124. package/src/forge/_generated/testGraph.json +2 -2
  125. package/src/forge/_generated/testGraph.ts +17 -7
  126. package/src/forge/_generated/testPlanRegistry.json +2 -2
  127. package/src/forge/_generated/testPlanRegistry.ts +2 -2
  128. package/src/forge/_generated/uiRoutes.json +1 -1
  129. package/src/forge/_generated/uiRoutes.ts +1 -1
  130. package/src/forge/_generated/uiScenarios.json +1 -1
  131. package/src/forge/_generated/uiScenarios.ts +1 -1
  132. package/src/forge/_generated/uiTestManifest.json +2 -2
  133. package/src/forge/_generated/uiTestManifest.ts +2 -2
  134. package/src/forge/_generated/workflowRegistry.json +2 -2
  135. package/src/forge/_generated/workflowRegistry.ts +3 -3
  136. package/src/forge/_generated/workflowSubscriptions.json +2 -2
  137. package/src/forge/_generated/workflowSubscriptions.ts +3 -3
  138. package/src/forge/cli/ai.ts +186 -1
  139. package/src/forge/cli/commands.ts +5 -0
  140. package/src/forge/cli/parse.ts +30 -3
  141. package/src/forge/compiler/agent-contract/build.ts +281 -8
  142. package/src/forge/compiler/agent-contract/types.ts +41 -0
  143. package/src/forge/compiler/ai-registry/build.ts +62 -1
  144. package/src/forge/compiler/ai-registry/constants.ts +1 -1
  145. package/src/forge/compiler/ai-registry/parse.ts +98 -4
  146. package/src/forge/compiler/app-graph/forge-apis.ts +1 -0
  147. package/src/forge/compiler/dev-manifest/build.ts +3 -0
  148. package/src/forge/compiler/make-registry/build.ts +13 -0
  149. package/src/forge/compiler/orchestrator/plan.ts +11 -0
  150. package/src/forge/compiler/orchestrator/serialize.ts +68 -0
  151. package/src/forge/compiler/types/ai-registry.ts +25 -1
  152. package/src/forge/compiler/types/app-graph.ts +1 -0
  153. package/src/forge/compiler/types/cli.ts +1 -0
  154. package/src/forge/compiler/types/dev-manifest.ts +3 -0
  155. package/src/forge/dev/server.ts +508 -1
  156. package/src/forge/make/index.ts +126 -3
  157. package/src/forge/make/templates.ts +188 -0
  158. package/src/forge/make/types.ts +1 -0
  159. package/src/forge/runtime/ai/context.ts +210 -5
  160. package/src/forge/runtime/ai/types.ts +70 -0
  161. package/src/forge/runtime/context/create-context.ts +30 -6
  162. package/src/forge/server.ts +82 -0
  163. package/src/forge/version.ts +1 -1
@@ -1,7 +1,7 @@
1
1
  import type { ForgeAiProvider } from "../types/ai-registry.ts";
2
2
 
3
3
  const AI_METHOD_PATTERN =
4
- /(?:ctx\.ai|ai)\.(generateText|streamText|generateStructured)\s*\(/g;
4
+ /(?:(?:ctx\.ai|ai)\.(generateText|streamText|generateStructured|runAgent)|ctx\.agent\.(run))\s*\(/g;
5
5
 
6
6
  const PROVIDER_PATTERN =
7
7
  /provider\s*:\s*["'](openai|anthropic|gateway)["']/;
@@ -11,7 +11,7 @@ const MODEL_PATTERN = /model\s*:\s*["']([^"']+)["']/;
11
11
  const PURPOSE_PATTERN = /purpose\s*:\s*["']([^"']+)["']/;
12
12
 
13
13
  export interface ParsedAiCall {
14
- method: "generateText" | "streamText" | "generateStructured";
14
+ method: "generateText" | "streamText" | "generateStructured" | "runAgent";
15
15
  provider?: ForgeAiProvider;
16
16
  model?: string;
17
17
  purpose?: string;
@@ -21,7 +21,7 @@ export function parseAiCallsFromSlice(sourceSlice: string): ParsedAiCall[] {
21
21
  const calls: ParsedAiCall[] = [];
22
22
 
23
23
  for (const match of sourceSlice.matchAll(AI_METHOD_PATTERN)) {
24
- const method = match[1] as ParsedAiCall["method"];
24
+ const method = (match[1] ?? (match[2] ? "runAgent" : "")) as ParsedAiCall["method"];
25
25
  const start = match.index ?? 0;
26
26
  const window = sourceSlice.slice(start, start + 600);
27
27
 
@@ -49,8 +49,102 @@ export function parseAiCallsFromSlice(sourceSlice: string): ParsedAiCall[] {
49
49
  return calls;
50
50
  }
51
51
 
52
- const FORBIDDEN_AI_CONTEXT_PATTERN = /ctx\.ai\./;
52
+ const FORBIDDEN_AI_CONTEXT_PATTERN = /ctx\.(?:ai\.|agent\.run\s*\()/;
53
53
 
54
54
  export function detectCtxAiUsage(sourceSlice: string): boolean {
55
55
  return FORBIDDEN_AI_CONTEXT_PATTERN.test(sourceSlice);
56
56
  }
57
+
58
+ const DESCRIPTION_PATTERN = /description\s*:\s*["'`]([^"'`]+)["'`]/;
59
+ const RISK_PATTERN = /risk\s*:\s*["'](read|write|external|destructive)["']/;
60
+ const STRICT_PATTERN = /strict\s*:\s*(true|false)/;
61
+ const NEEDS_APPROVAL_PATTERN = /needsApproval\s*:\s*(true|false|async\s*\(|\([^)]*\)\s*=>|[A-Za-z_$][A-Za-z0-9_$]*)/;
62
+ const INSTRUCTIONS_PATTERN = /instructions\s*:\s*["'`]([^"'`]+)["'`]/;
63
+ const TOOL_ARRAY_PATTERN = /tools\s*:\s*\[([^\]]*)\]/s;
64
+ const TOOL_OBJECT_PATTERN = /tools\s*:\s*\{([^}]*)\}/s;
65
+ const STOP_TOOL_PATTERN = /stopWhen\s*:\s*\{[^}]*kind\s*:\s*["']toolCall["'][^}]*toolName\s*:\s*["']([^"']+)["'][^}]*\}/s;
66
+ const STOP_STEP_PATTERN = /stopWhen\s*:\s*\{[^}]*kind\s*:\s*["']stepCount["'][^}]*maxSteps\s*:\s*(\d+)[^}]*\}/s;
67
+ const MAX_STEPS_PATTERN = /maxSteps\s*:\s*(\d+)/;
68
+
69
+ export interface ParsedAiToolMeta {
70
+ description?: string;
71
+ risk: "read" | "write" | "external" | "destructive" | "unknown";
72
+ strict: boolean;
73
+ needsApproval: boolean | "dynamic";
74
+ }
75
+
76
+ export interface ParsedAiAgentMeta {
77
+ provider?: ForgeAiProvider;
78
+ model?: string;
79
+ instructions?: string;
80
+ tools: string[];
81
+ stopWhen:
82
+ | { kind: "stepCount"; maxSteps: number }
83
+ | { kind: "toolCall"; toolName: string }
84
+ | { kind: "default" };
85
+ }
86
+
87
+ function parseBooleanOrDynamic(value: string | undefined): boolean | "dynamic" {
88
+ if (value === "true") return true;
89
+ if (value === "false") return false;
90
+ return "dynamic";
91
+ }
92
+
93
+ function parseStringList(raw: string | undefined): string[] {
94
+ if (!raw) return [];
95
+ return [...raw.matchAll(/["'`]([^"'`]+)["'`]/g)]
96
+ .map((match) => match[1] ?? "")
97
+ .filter(Boolean)
98
+ .sort();
99
+ }
100
+
101
+ function parseObjectToolKeys(raw: string | undefined): string[] {
102
+ if (!raw) return [];
103
+ const explicit = [...raw.matchAll(/([A-Za-z_$][A-Za-z0-9_$]*)\s*:/g)]
104
+ .map((match) => match[1] ?? "")
105
+ .filter(Boolean);
106
+ const shorthand = raw
107
+ .split(",")
108
+ .map((part) => part.trim())
109
+ .filter((part) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(part));
110
+ return [...new Set([...explicit, ...shorthand])].sort();
111
+ }
112
+
113
+ export function parseAiToolMeta(sourceSlice: string): ParsedAiToolMeta {
114
+ const description = DESCRIPTION_PATTERN.exec(sourceSlice)?.[1];
115
+ const risk = RISK_PATTERN.exec(sourceSlice)?.[1] as ParsedAiToolMeta["risk"] | undefined;
116
+ const strict = STRICT_PATTERN.exec(sourceSlice)?.[1] === "true";
117
+ const needsApprovalMatch = NEEDS_APPROVAL_PATTERN.exec(sourceSlice)?.[1];
118
+
119
+ return {
120
+ ...(description ? { description } : {}),
121
+ risk: risk ?? "unknown",
122
+ strict,
123
+ needsApproval: needsApprovalMatch
124
+ ? parseBooleanOrDynamic(needsApprovalMatch)
125
+ : false,
126
+ };
127
+ }
128
+
129
+ export function parseAiAgentMeta(sourceSlice: string): ParsedAiAgentMeta {
130
+ const provider = PROVIDER_PATTERN.exec(sourceSlice)?.[1] as ForgeAiProvider | undefined;
131
+ const model = MODEL_PATTERN.exec(sourceSlice)?.[1];
132
+ const instructions = INSTRUCTIONS_PATTERN.exec(sourceSlice)?.[1];
133
+ const arrayTools = parseStringList(TOOL_ARRAY_PATTERN.exec(sourceSlice)?.[1]);
134
+ const objectTools = parseObjectToolKeys(TOOL_OBJECT_PATTERN.exec(sourceSlice)?.[1]);
135
+ const stopTool = STOP_TOOL_PATTERN.exec(sourceSlice)?.[1];
136
+ const stopStepsRaw =
137
+ STOP_STEP_PATTERN.exec(sourceSlice)?.[1] ?? MAX_STEPS_PATTERN.exec(sourceSlice)?.[1];
138
+
139
+ return {
140
+ ...(provider ? { provider } : {}),
141
+ ...(model ? { model } : {}),
142
+ ...(instructions ? { instructions } : {}),
143
+ tools: [...new Set([...arrayTools, ...objectTools])].sort(),
144
+ stopWhen: stopTool
145
+ ? { kind: "toolCall", toolName: stopTool }
146
+ : stopStepsRaw
147
+ ? { kind: "stepCount", maxSteps: Number(stopStepsRaw) }
148
+ : { kind: "default" },
149
+ };
150
+ }
@@ -13,6 +13,7 @@ export const FORGE_BUILDER_APIS: Readonly<Record<string, ForgeKind>> = {
13
13
  definePolicies: "policy",
14
14
  workflow: "workflow",
15
15
  agent: "agent",
16
+ aiTool: "aiTool",
16
17
  telemetryEvent: "telemetryEvent",
17
18
  };
18
19
 
@@ -61,6 +61,9 @@ function buildRoutes(
61
61
  { method: "GET", path: "/health", purpose: "health" },
62
62
  { method: "GET", path: "/entries", purpose: "entries" },
63
63
  { method: "GET", path: "/queries", purpose: "queries" },
64
+ { method: "POST", path: "/ai/agents/chat", purpose: "ai-agent-chat" },
65
+ { method: "POST", path: "/ai/agents/run", purpose: "ai-agent-run" },
66
+ { method: "GET", path: "/ai/providers", purpose: "ai-providers" },
64
67
  { method: "GET", path: "/workflows", purpose: "workflows" },
65
68
  { method: "GET", path: "/workflows/runs", purpose: "workflow-runs" },
66
69
  { method: "POST", path: "/workflows/process", purpose: "workflow-process" },
@@ -34,6 +34,7 @@ export function buildMakeRegistry(generatorVersion: string): MakeRegistryArtifac
34
34
  "forge make list --json",
35
35
  "forge make explain <primitive> --json",
36
36
  "forge make ui --framework vite --dry-run --json",
37
+ "forge make ai-chat support --dry-run --json",
37
38
  "forge make resource <name> --fields title:text,status:enum(open,closed) --dry-run --json",
38
39
  "forge make resource <name> --fields title:text --with-ui --yes",
39
40
  "forge make apply <planId>",
@@ -123,6 +124,17 @@ export function buildMakeRegistry(generatorVersion: string): MakeRegistryArtifac
123
124
  modifies: [],
124
125
  examples: ["forge make ui --framework vite --yes"],
125
126
  },
127
+ {
128
+ name: "ai-chat",
129
+ summary: "Add a Forge AI agent and React chat component backed by /ai/agents/run.",
130
+ creates: [
131
+ "src/ai/<name>Agent.ts",
132
+ "web/components/<Name>AiChat.tsx",
133
+ "web/app/<name>-ai/page.tsx when web/app exists",
134
+ ],
135
+ modifies: [],
136
+ examples: ["forge make ai-chat support --yes"],
137
+ },
126
138
  {
127
139
  name: "resource",
128
140
  summary: "Add schema, policies, CRUD, queries, liveQuery, optional UI, and tests.",
@@ -155,6 +167,7 @@ export function buildMakeTemplates(): MakeTemplateArtifact {
155
167
  { name: "component", sourceKind: "frontend", outputPattern: "web/components/<name>.tsx" },
156
168
  { name: "page", sourceKind: "frontend", outputPattern: "web/app/<route>/page.tsx" },
157
169
  { name: "ui", sourceKind: "frontend", outputPattern: "web/src/App.tsx" },
170
+ { name: "ai-chat", sourceKind: "frontend", outputPattern: "web/components/<name>AiChat.tsx" },
158
171
  { name: "placeholder-test", sourceKind: "test", outputPattern: "tests/make-generated/<name>.test.ts" },
159
172
  ],
160
173
  };
@@ -54,6 +54,8 @@ import { buildDevManifest } from "../dev-manifest/build.ts";
54
54
  import { buildRuntimeGraph } from "../runtime-graph/build.ts";
55
55
  import {
56
56
  buildAgentContractArtifacts,
57
+ serializeAgentToolRegistryJson,
58
+ serializeAgentToolRegistryTs,
57
59
  serializeCapabilityMapJson,
58
60
  serializeCapabilityMapTs,
59
61
  serializeAgentContractJson,
@@ -399,6 +401,15 @@ export function plan(input: PlanInput): EmitPlan {
399
401
  serializeAgentContractJson(agentArtifacts.contract),
400
402
  ),
401
403
  makeEmitFile(`${GENERATED_DIR}/appMap.md`, agentArtifacts.appMapMd),
404
+ makeEmitFile(
405
+ `${GENERATED_DIR}/agentTools.ts`,
406
+ serializeAgentToolRegistryTs(agentArtifacts.toolRegistry),
407
+ ),
408
+ makeEmitFile(
409
+ `${GENERATED_DIR}/agentTools.json`,
410
+ serializeAgentToolRegistryJson(agentArtifacts.toolRegistry),
411
+ ),
412
+ makeEmitFile(`${GENERATED_DIR}/agentTools.md`, agentArtifacts.agentToolsMd),
402
413
  makeEmitFile(
403
414
  `${GENERATED_DIR}/capabilityMap.ts`,
404
415
  serializeCapabilityMapTs(agentArtifacts.capabilityMap),
@@ -680,6 +680,8 @@ export function serializeAiRegistryJson(registry: import("../types/ai-registry.t
680
680
  inputHash: registry.inputHash,
681
681
  providers: registry.providers,
682
682
  generations: registry.generations,
683
+ tools: registry.tools,
684
+ agents: registry.agents,
683
685
  diagnostics: registry.diagnostics,
684
686
  };
685
687
  return serializeCanonical(payload);
@@ -762,10 +764,76 @@ export interface ForgeGenerateStructuredInput<T> {
762
764
  schema: ForgeFlexibleSchema<T>;
763
765
  }
764
766
 
767
+ export type ForgeAiToolRisk = "read" | "write" | "external" | "destructive";
768
+
769
+ export interface ForgeAiToolRuntimeContext {
770
+ secrets: {
771
+ get(name: string): string;
772
+ optional(name: string): string | undefined;
773
+ has(name: string): boolean;
774
+ };
775
+ env: Record<string, string | undefined>;
776
+ telemetry?: {
777
+ traceId?: string;
778
+ capture(name: string, properties?: Record<string, unknown>): Promise<void>;
779
+ };
780
+ auth?: unknown;
781
+ }
782
+
783
+ export interface ForgeAiToolDefinition<TArgs = unknown, TResult = unknown> {
784
+ description: string;
785
+ inputSchema: unknown;
786
+ outputSchema?: unknown;
787
+ strict?: boolean;
788
+ needsApproval?: boolean | ((args: TArgs) => boolean | Promise<boolean>);
789
+ risk?: ForgeAiToolRisk;
790
+ handler: (
791
+ ctx: ForgeAiToolRuntimeContext,
792
+ args: TArgs,
793
+ ) => TResult | Promise<TResult>;
794
+ }
795
+
796
+ export type ForgeAgentStopWhen =
797
+ | { kind: "stepCount"; maxSteps: number }
798
+ | { kind: "toolCall"; toolName: string };
799
+
800
+ export interface ForgeRunAgentInput {
801
+ provider?: ForgeAiProvider;
802
+ model: string;
803
+ prompt: string;
804
+ instructions: string;
805
+ purpose?: string;
806
+ tools?: Record<string, ForgeAiToolDefinition>;
807
+ stopWhen?: ForgeAgentStopWhen;
808
+ maxSteps?: number;
809
+ temperature?: number;
810
+ maxTokens?: number;
811
+ }
812
+
813
+ export interface ForgeRunAgentResult {
814
+ text: string;
815
+ provider: ForgeAiProvider;
816
+ model: string;
817
+ purpose?: string;
818
+ usage: ForgeAiUsage;
819
+ latencyMs: number;
820
+ toolCalls: Array<{
821
+ toolName: string;
822
+ input: unknown;
823
+ }>;
824
+ toolResults: Array<{
825
+ toolName: string;
826
+ output: unknown;
827
+ }>;
828
+ steps: number;
829
+ estimatedCostUsd?: number;
830
+ }
831
+
765
832
  export interface AiContext {
766
833
  generateText(input: ForgeGenerateTextInput): Promise<ForgeGenerateTextResult>;
767
834
  streamText(input: ForgeStreamTextInput): Promise<ForgeStreamTextResult>;
768
835
  generateStructured<T>(input: ForgeGenerateStructuredInput<T>): Promise<T>;
836
+ runAgent(input: ForgeRunAgentInput): Promise<ForgeRunAgentResult>;
769
837
  }
770
838
  `;
771
839
  }
@@ -18,10 +18,32 @@ export interface AiGenerationCall {
18
18
  provider: ForgeAiProvider;
19
19
  model: string;
20
20
  purpose?: string;
21
- method: "generateText" | "streamText" | "generateStructured";
21
+ method: "generateText" | "streamText" | "generateStructured" | "runAgent";
22
22
  file: string;
23
23
  }
24
24
 
25
+ export interface AiToolDefinition {
26
+ name: string;
27
+ file: string;
28
+ description?: string;
29
+ risk: "read" | "write" | "external" | "destructive" | "unknown";
30
+ strict: boolean;
31
+ needsApproval: boolean | "dynamic";
32
+ }
33
+
34
+ export interface AiAgentDefinition {
35
+ name: string;
36
+ file: string;
37
+ provider: ForgeAiProvider;
38
+ model: string;
39
+ instructions?: string;
40
+ tools: string[];
41
+ stopWhen:
42
+ | { kind: "stepCount"; maxSteps: number }
43
+ | { kind: "toolCall"; toolName: string }
44
+ | { kind: "default" };
45
+ }
46
+
25
47
  export interface AiRegistry {
26
48
  schemaVersion: string;
27
49
  generatorVersion: string;
@@ -29,5 +51,7 @@ export interface AiRegistry {
29
51
  inputHash: string;
30
52
  providers: AiProviderDefinition[];
31
53
  generations: AiGenerationCall[];
54
+ tools: AiToolDefinition[];
55
+ agents: AiAgentDefinition[];
32
56
  diagnostics: unknown[];
33
57
  }
@@ -12,6 +12,7 @@ export type ForgeKind =
12
12
  | "policy"
13
13
  | "workflow"
14
14
  | "agent"
15
+ | "aiTool"
15
16
  | "telemetryEvent";
16
17
 
17
18
  export interface ForgeSymbol {
@@ -79,6 +79,7 @@ export type InspectTarget =
79
79
  | "test-graph"
80
80
  | "test-plans"
81
81
  | "agent-contract"
82
+ | "agent-tools"
82
83
  | "agent-adapters"
83
84
  | "capability-map"
84
85
  | "framework"
@@ -11,6 +11,9 @@ export interface DevRoute {
11
11
  | "workflows"
12
12
  | "workflow-runs"
13
13
  | "workflow-process"
14
+ | "ai-agent-chat"
15
+ | "ai-agent-run"
16
+ | "ai-providers"
14
17
  | "queries"
15
18
  | "query";
16
19
  entryName?: string;