Showing the changes to packages/plugins/openapi/src (2 of 24 files). Show all
Unified · Split
| @@ -212,7 +212,7 @@ layer(TestLayer)("OpenAPI Plugin", (it) => { · 211 unmodified lines | |||
| 212 | }), | 212 | }), |
| 213 | ); | 213 | ); |
| 214 | 214 | ||
| 215 | it.effect("registers static openapi control tools", () => | 215 | it.effect("registers static openapi executor tools", () => |
| 216 | Effect.gen(function* () { | 216 | Effect.gen(function* () { |
| 217 | const httpClient = yield* HttpClient.HttpClient; | 217 | const httpClient = yield* HttpClient.HttpClient; |
| 218 | const clientLayer = Layer.succeed(HttpClient.HttpClient, httpClient); | 218 | const clientLayer = Layer.succeed(HttpClient.HttpClient, httpClient); |
| @@ -228,12 +228,12 @@ layer(TestLayer)("OpenAPI Plugin", (it) => { · 9 unmodified lines | |||
| 228 | 228 | ||
| 229 | const tools = yield* executor.tools.list(); | 229 | const tools = yield* executor.tools.list(); |
| 230 | const ids = tools.map((t) => t.id); | 230 | const ids = tools.map((t) => t.id); |
| 231 | expect(ids).toContain("openapi.previewSpec"); | 231 | expect(ids).toContain("executor.openapi.previewSpec"); |
| 232 | expect(ids).toContain("openapi.addSource"); | 232 | expect(ids).toContain("executor.openapi.addSource"); |
| 233 | }), | 233 | }), |
| 234 | ); | 234 | ); |
| 235 | 235 | ||
| 236 | it.effect("lists openapi as a static runtime source", () => | 236 | it.effect("lists executor as the static runtime source", () => |
| 237 | Effect.gen(function* () { | 237 | Effect.gen(function* () { |
| 238 | const httpClient = yield* HttpClient.HttpClient; | 238 | const httpClient = yield* HttpClient.HttpClient; |
| 239 | const clientLayer = Layer.succeed(HttpClient.HttpClient, httpClient); | 239 | const clientLayer = Layer.succeed(HttpClient.HttpClient, httpClient); |
| @@ -248,7 +248,8 @@ layer(TestLayer)("OpenAPI Plugin", (it) => { · 8 unmodified lines | |||
| 248 | ); | 248 | ); |
| 249 | 249 | ||
| 250 | const sources = yield* executor.sources.list(); | 250 | const sources = yield* executor.sources.list(); |
| 251 | const control = sources.find((s) => s.id === "openapi"); | 251 | expect(sources.find((s) => s.id === "openapi")).toBeUndefined(); |
| 252 | const control = sources.find((s) => s.id === "executor"); | ||
| 252 | expect(control).toBeDefined(); | 253 | expect(control).toBeDefined(); |
| 253 | expect(control!.runtime).toBe(true); | 254 | expect(control!.runtime).toBe(true); |
| 254 | expect(control!.canRemove).toBe(false); | 255 | expect(control!.canRemove).toBe(false); |
| @@ -270,7 +271,7 @@ layer(TestLayer)("OpenAPI Plugin", (it) => { · 15 unmodified lines | |||
| 270 | ); | 271 | ); |
| 271 | 272 | ||
| 272 | const result = (yield* executor.tools.invoke( | 273 | const result = (yield* executor.tools.invoke( |
| 273 | "openapi.previewSpec", | 274 | "executor.openapi.previewSpec", |
| 274 | { spec: specJson }, | 275 | { spec: specJson }, |
| 275 | autoApprove, | 276 | autoApprove, |
| 276 | )) as { operationCount: number }; | 277 | )) as { operationCount: number }; |
| @@ -279,6 +280,26 @@ layer(TestLayer)("OpenAPI Plugin", (it) => { · 2 unmodified lines | |||
| 279 | }), | 280 | }), |
| 280 | ); | 281 | ); |
| 281 | 282 | ||
| 283 | it.effect("describes static addSource parameters from Standard Schema", () => | ||
| 284 | Effect.gen(function* () { | ||
| 285 | const executor = yield* createExecutor( | ||
| 286 | makeTestConfig({ | ||
| 287 | plugins: [openApiPlugin(), memorySecretsPlugin()] as const, | ||
| 288 | }), | ||
| 289 | ); | ||
| 290 | |||
| 291 | const schema = yield* executor.tools.schema("executor.openapi.addSource"); | ||
| 292 | |||
| 293 | expect(schema).not.toBeNull(); | ||
| 294 | expect(schema!.inputTypeScript).toContain("scope: string"); | ||
| 295 | expect(schema!.inputTypeScript).toContain("spec: string"); | ||
| 296 | expect( | ||
| 297 | (schema!.inputSchema as { properties?: Record<string, unknown> }).properties, | ||
| 298 | ).toHaveProperty("credentialTargetScope"); | ||
| 299 | expect(schema!.inputTypeScript).not.toBe("Record<string, unknown>"); | ||
| 300 | }), | ||
| 301 | ); | ||
| 302 | |||
| 282 | it.effect("invokes static addSource through executor.tools.invoke", () => | 303 | it.effect("invokes static addSource through executor.tools.invoke", () => |
| 283 | Effect.gen(function* () { | 304 | Effect.gen(function* () { |
| 284 | const httpClient = yield* HttpClient.HttpClient; | 305 | const httpClient = yield* HttpClient.HttpClient; |
| @@ -300,7 +321,7 @@ layer(TestLayer)("OpenAPI Plugin", (it) => { · 15 unmodified lines | |||
| 300 | ); | 321 | ); |
| 301 | 322 | ||
| 302 | const result = (yield* executor.tools.invoke( | 323 | const result = (yield* executor.tools.invoke( |
| 303 | "openapi.addSource", | 324 | "executor.openapi.addSource", |
| 304 | { scope: String(orgScope), spec: specJson, namespace: "runtime" }, | 325 | { scope: String(orgScope), spec: specJson, namespace: "runtime" }, |
| 305 | autoApprove, | 326 | autoApprove, |
| 306 | )) as { sourceId: string; toolCount: number }; | 327 | )) as { sourceId: string; toolCount: number }; |
| @@ -322,7 +343,7 @@ layer(TestLayer)("OpenAPI Plugin", (it) => { · 15 unmodified lines | |||
| 322 | 343 | ||
| 323 | const declined = yield* executor.tools | 344 | const declined = yield* executor.tools |
| 324 | .invoke( | 345 | .invoke( |
| 325 | "openapi.addSource", | 346 | "executor.openapi.addSource", |
| 326 | { scope: TEST_SCOPE, spec: specJson, namespace: "runtime_declined" }, | 347 | { scope: TEST_SCOPE, spec: specJson, namespace: "runtime_declined" }, |
| 327 | { onElicitation: () => Effect.succeed({ action: "decline" as const }) }, | 348 | { onElicitation: () => Effect.succeed({ action: "decline" as const }) }, |
| 328 | ) | 349 | ) |
| @@ -825,7 +846,7 @@ layer(TestLayer)("OpenAPI Plugin", (it) => { · 496 unmodified lines | |||
| 825 | 846 | ||
| 826 | const remaining = yield* executor.tools.list(); | 847 | const remaining = yield* executor.tools.list(); |
| 827 | const ids = remaining.map((t) => t.id).sort(); | 848 | const ids = remaining.map((t) => t.id).sort(); |
| 828 | expect(ids).toEqual(["openapi.addSource", "openapi.previewSpec"]); | 849 | expect(ids).toEqual(["executor.openapi.addSource", "executor.openapi.previewSpec"]); |
| 829 | }), | 850 | }), |
| 830 | ); | 851 | ); |
| 831 | 852 | ||
| @@ -8,6 +8,7 @@ import { · 7 unmodified lines | |||
| 8 | SourceDetectionResult, | 8 | SourceDetectionResult, |
| 9 | StorageError, | 9 | StorageError, |
| 10 | definePlugin, | 10 | definePlugin, |
| 11 | tool, | ||
| 11 | resolveSecretBackedMap, | 12 | resolveSecretBackedMap, |
| 12 | type CredentialBindingRef, | 13 | type CredentialBindingRef, |
| 13 | type PluginCtx, | 14 | type PluginCtx, |
| @@ -169,7 +170,6 @@ const PreviewSpecInputSchema = Schema.Struct({ · 155 unmodified lines | |||
| 169 | }), | 170 | }), |
| 170 | ), | 171 | ), |
| 171 | }); | 172 | }); |
| 172 | type PreviewSpecInput = typeof PreviewSpecInputSchema.Type; | ||
| 173 | 173 | ||
| 174 | const OpenApiHeaderInputSchema = Schema.Union([HeaderValueSchema, ConfiguredHeaderValueSchema]); | 174 | const OpenApiHeaderInputSchema = Schema.Union([HeaderValueSchema, ConfiguredHeaderValueSchema]); |
| 175 | const OpenApiOAuthInputSchema = OAuth2SourceConfig; | 175 | const OpenApiOAuthInputSchema = OAuth2SourceConfig; |
| @@ -191,7 +191,21 @@ const AddSourceInputSchema = Schema.Struct({ · 15 unmodified lines | |||
| 191 | }), | 191 | }), |
| 192 | ), | 192 | ), |
| 193 | }); | 193 | }); |
| 194 | type AddSourceInput = typeof AddSourceInputSchema.Type; | 194 | |
| 195 | const AddSourceOutputSchema = Schema.Struct({ | ||
| 196 | sourceId: Schema.String, | ||
| 197 | toolCount: Schema.Number, | ||
| 198 | }); | ||
| 199 | |||
| 200 | const PreviewSpecInputStandardSchema = Schema.toStandardSchemaV1( | ||
| 201 | Schema.toStandardJSONSchemaV1(PreviewSpecInputSchema), | ||
| 202 | ); | ||
| 203 | const AddSourceInputStandardSchema = Schema.toStandardSchemaV1( | ||
| 204 | Schema.toStandardJSONSchemaV1(AddSourceInputSchema), | ||
| 205 | ); | ||
| 206 | const AddSourceOutputStandardSchema = Schema.toStandardSchemaV1( | ||
| 207 | Schema.toStandardJSONSchemaV1(AddSourceOutputSchema), | ||
| 208 | ); | ||
| 195 | 209 | ||
| 196 | // --------------------------------------------------------------------------- | 210 | // --------------------------------------------------------------------------- |
| 197 | // Helpers | 211 | // Helpers |
| @@ -1172,60 +1186,26 @@ export const openApiPlugin = definePlugin((options?: OpenApiPluginOptions) => { · 974 unmodified lines | |||
| 1172 | staticSources: (self) => [ | 1186 | staticSources: (self) => [ |
| 1173 | { | 1187 | { |
| 1174 | id: "openapi", | 1188 | id: "openapi", |
| 1175 | kind: "control", | 1189 | kind: "executor", |
| 1176 | name: "OpenAPI", | 1190 | name: "OpenAPI", |
| 1177 | tools: [ | 1191 | tools: [ |
| 1178 | { | 1192 | tool({ |
| 1179 | name: "previewSpec", | 1193 | name: "previewSpec", |
| 1180 | description: "Preview an OpenAPI document before adding it as a source", | 1194 | description: "Preview an OpenAPI document before adding it as a source", |
| 1181 | inputSchema: { | 1195 | inputSchema: PreviewSpecInputStandardSchema, |
| 1182 | type: "object", | 1196 | execute: (input) => self.previewSpec(input), |
| 1183 | properties: { | 1197 | }), |
| 1184 | spec: { type: "string" }, | 1198 | tool({ |
| 1185 | specFetchCredentials: { type: "object" }, | ||
| 1186 | }, | ||
| 1187 | required: ["spec"], | ||
| 1188 | }, | ||
| 1189 | handler: ({ args }) => self.previewSpec(args as PreviewSpecInput), | ||
| 1190 | }, | ||
| 1191 | { | ||
| 1192 | name: "addSource", | 1199 | name: "addSource", |
| 1193 | description: "Add an OpenAPI source and register its operations as tools", | 1200 | description: "Add an OpenAPI source and register its operations as tools", |
| 1194 | annotations: { | 1201 | annotations: { |
| 1195 | requiresApproval: true, | 1202 | requiresApproval: true, |
| 1196 | approvalDescription: "Add an OpenAPI source", | 1203 | approvalDescription: "Add an OpenAPI source", |
| 1197 | }, | 1204 | }, |
| 1198 | inputSchema: { | 1205 | inputSchema: AddSourceInputStandardSchema, |
| 1199 | type: "object", | 1206 | outputSchema: AddSourceOutputStandardSchema, |
| 1200 | properties: { | 1207 | execute: (input) => self.addSpec(input), |
| 1201 | scope: { type: "string" }, | 1208 | }), |
| 1202 | spec: { type: "string" }, | ||
| 1203 | name: { type: "string" }, | ||
| 1204 | baseUrl: { type: "string" }, | ||
| 1205 | namespace: { type: "string" }, | ||
| 1206 | headers: { type: "object" }, | ||
| 1207 | queryParams: { type: "object" }, | ||
| 1208 | oauth2: { type: "object" }, | ||
| 1209 | credentialTargetScope: { type: "string" }, | ||
| 1210 | specFetchCredentials: { type: "object" }, | ||
| 1211 | }, | ||
| 1212 | required: ["scope", "spec"], | ||
| 1213 | }, | ||
| 1214 | outputSchema: { | ||
| 1215 | type: "object", | ||
| 1216 | properties: { | ||
| 1217 | sourceId: { type: "string" }, | ||
| 1218 | toolCount: { type: "number" }, | ||
| 1219 | }, | ||
| 1220 | required: ["sourceId", "toolCount"], | ||
| 1221 | }, | ||
| 1222 | handler: ({ args }) => | ||
| 1223 | Effect.gen(function* () { | ||
| 1224 | const input: AddSourceInput = | ||
| 1225 | yield* Schema.decodeUnknownEffect(AddSourceInputSchema)(args); | ||
| 1226 | return yield* self.addSpec(input); | ||
| 1227 | }), | ||
| 1228 | }, | ||
| 1229 | ], | 1209 | ], |
| 1230 | }, | 1210 | }, |
| 1231 | ], | 1211 | ], |