From cd03f0dcf513cd6830435da4f40e3b6beb8ed797 Mon Sep 17 00:00:00 2001 From: Nadeesha Cabral Date: Fri, 6 Dec 2024 10:18:13 +1100 Subject: [PATCH 1/3] feat: Introduce server stats endpoint and caching --- app/client/contract.ts | 98 +++++++++++++---------- control-plane/src/modules/contract.ts | 24 ++++-- control-plane/src/modules/router.ts | 9 +++ control-plane/src/modules/server-stats.ts | 52 ++++++++++++ 4 files changed, 135 insertions(+), 48 deletions(-) create mode 100644 control-plane/src/modules/server-stats.ts diff --git a/app/client/contract.ts b/app/client/contract.ts index 9be2f63b..1d0927c4 100644 --- a/app/client/contract.ts +++ b/app/client/contract.ts @@ -48,7 +48,7 @@ export const VersionedTextsSchema = z.object({ z.object({ version: z.string(), content: z.string(), - }), + }) ), }); @@ -88,7 +88,7 @@ export const learningSchema = z.object({ summary: z .string() .describe( - "The new information that was learned. Be generic, do not refer to the entities.", + "The new information that was learned. Be generic, do not refer to the entities." ), entities: z .array( @@ -97,7 +97,7 @@ export const learningSchema = z.object({ .string() .describe("The name of the entity this learning relates to."), type: z.enum(["tool"]), - }), + }) ) .describe("The entities this learning relates to."), relevance: z.object({ @@ -121,7 +121,7 @@ export const agentDataSchema = z toolName: z.string(), reasoning: z.string().optional(), input: z.object({}).passthrough(), - }), + }) ) .optional(), }) @@ -162,7 +162,7 @@ export const definition = { description: z.string().optional(), schema: z.string().optional(), config: FunctionConfigSchema.optional(), - }), + }) ) .optional(), }), @@ -231,7 +231,7 @@ export const definition = { .and( z.object({ data: z.string(), - }), + }) ), }, getContract: { @@ -256,7 +256,7 @@ export const definition = { name: z.string(), createdAt: z.date(), description: z.string().nullable(), - }), + }) ), 401: z.undefined(), }, @@ -332,13 +332,13 @@ export const definition = { name: z.string().optional(), description: z.string().optional(), additionalContext: VersionedTextsSchema.optional().describe( - "Additional cluster context which is included in all runs", + "Additional cluster context which is included in all runs" ), debug: z .boolean() .optional() .describe( - "Enable additional logging (Including prompts and results) for use by Inferable support", + "Enable additional logging (Including prompts and results) for use by Inferable support" ), enableRunConfigs: z.boolean().optional(), enableKnowledgebase: z.boolean().optional(), @@ -389,7 +389,7 @@ export const definition = { workflowId: z.string().nullable(), meta: z.any().nullable(), id: z.string(), - }), + }) ), 401: z.undefined(), 404: z.undefined(), @@ -418,13 +418,13 @@ export const definition = { totalInputTokens: z.number(), totalOutputTokens: z.number(), totalModelInvocations: z.number(), - }), + }) ), agentRuns: z.array( z.object({ date: z.string(), totalAgentRuns: z.number(), - }), + }) ), }), }, @@ -481,23 +481,23 @@ export const definition = { resultSchema: anyObject .optional() .describe( - "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema", + "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema" ), attachedFunctions: z .array(functionReference) .optional() .describe( - "An array of functions to make available to the run. By default all functions in the cluster will be available", + "An array of functions to make available to the run. By default all functions in the cluster will be available" ), onStatusChange: z .object({ function: functionReference.describe( - "A function to call when the run status changes", + "A function to call when the run status changes" ), }) .optional() .describe( - "Mechanism for receiving notifications when the run status changes", + "Mechanism for receiving notifications when the run status changes" ), metadata: z .record(z.string()) @@ -513,16 +513,16 @@ export const definition = { .object({}) .passthrough() .describe("The mock output of the function"), - }), + }) ) .optional() .describe( - "Function mocks to be used in the run. (Keys should be function in the format _)", + "Function mocks to be used in the run. (Keys should be function in the format _)" ), }) .optional() .describe( - "When provided, the run will be marked as as a test / evaluation", + "When provided, the run will be marked as as a test / evaluation" ), config: z .object({ @@ -531,7 +531,7 @@ export const definition = { .object({}) .passthrough() .describe( - "The run configuration input arguments, the schema must match the run configuration input schema", + "The run configuration input arguments, the schema must match the run configuration input schema" ) .optional(), }) @@ -560,7 +560,7 @@ export const definition = { .boolean() .default(true) .describe( - "Allow the run to be continued with follow-up messages / message edits", + "Allow the run to be continued with follow-up messages / message edits" ), }), responses: { @@ -638,7 +638,7 @@ export const definition = { createdAt: z.date(), pending: z.boolean().default(false), displayableContext: z.record(z.string()).nullable(), - }), + }) ), 401: z.undefined(), }, @@ -676,7 +676,7 @@ export const definition = { configId: z.string().nullable(), configVersion: z.number().nullable(), feedbackScore: z.number().nullable(), - }), + }) ), 401: z.undefined(), }, @@ -840,7 +840,7 @@ export const definition = { targetFn: z.string(), service: z.string(), executingMachineId: z.string().nullable(), - }), + }) ), }, }, @@ -876,7 +876,7 @@ export const definition = { createdAt: z.date(), createdBy: z.string(), revokedAt: z.date().nullable(), - }), + }) ), }, }, @@ -906,7 +906,7 @@ export const definition = { id: z.string(), lastPingAt: z.date(), ip: z.string(), - }), + }) ), }, pathParams: z.object({ @@ -932,10 +932,10 @@ export const definition = { description: z.string().optional(), schema: z.string().optional(), config: FunctionConfigSchema.optional(), - }), + }) ) .optional(), - }), + }) ), }, pathParams: z.object({ @@ -974,7 +974,7 @@ export const definition = { createdAt: z.date(), pending: z.boolean().default(false), displayableContext: z.record(z.string()).nullable(), - }), + }) ), activity: z.array( z.object({ @@ -985,7 +985,7 @@ export const definition = { createdAt: z.date(), jobId: z.string().nullable(), targetFn: z.string().nullable(), - }), + }) ), jobs: z.array( z.object({ @@ -997,7 +997,7 @@ export const definition = { createdAt: z.date(), approved: z.boolean().nullable(), approvalRequested: z.boolean().nullable(), - }), + }) ), run: z.object({ id: z.string(), @@ -1111,7 +1111,7 @@ export const definition = { resultSchema: anyObject.nullable(), inputSchema: anyObject.nullable(), public: z.boolean(), - }), + }) ), }), 401: z.undefined(), @@ -1216,7 +1216,7 @@ export const definition = { resultSchema: z.unknown().nullable(), createdAt: z.date(), updatedAt: z.date(), - }), + }) ), 401: z.undefined(), }, @@ -1243,7 +1243,7 @@ export const definition = { createdAt: z.date(), updatedAt: z.date(), similarity: z.number(), - }), + }) ), 401: z.undefined(), }, @@ -1263,7 +1263,7 @@ export const definition = { jobFailureCount: z.number(), timeToCompletion: z.number(), jobCount: z.number(), - }), + }) ), }, pathParams: z.object({ @@ -1284,7 +1284,7 @@ export const definition = { .array(z.string()) .transform((tags) => tags.map((tag) => tag.toLowerCase().trim())), title: z.string(), - }), + }) ), }), responses: { @@ -1312,7 +1312,7 @@ export const definition = { tags: z.array(z.string()), title: z.string(), similarity: z.number(), - }), + }) ), 401: z.undefined(), }, @@ -1363,7 +1363,7 @@ export const definition = { data: z.string(), tags: z.array(z.string()), title: z.string(), - }), + }) ), 401: z.undefined(), }, @@ -1393,7 +1393,7 @@ export const definition = { .max(20) .default(0) .describe( - "Time in seconds to keep the request open waiting for a response", + "Time in seconds to keep the request open waiting for a response" ), }), headers: z.object({ @@ -1471,7 +1471,7 @@ export const definition = { authContext: z.any().nullable(), runContext: z.any().nullable(), approved: z.boolean(), - }), + }) ), }, }, @@ -1503,7 +1503,7 @@ export const definition = { resultSchema: anyObject .optional() .describe( - "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema", + "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema" ), modelId: z.enum(["claude-3-5-sonnet", "claude-3-haiku"]), temperature: z @@ -1520,6 +1520,22 @@ export const definition = { clusterId: z.string(), }), }, + getServerStats: { + method: "GET", + path: "/stats", + responses: { + 200: z.object({ + functionCalls: z.object({ + count: z.number(), + }), + tokenUsage: z.object({ + input: z.number(), + output: z.number(), + }), + refreshedAt: z.number(), + }), + }, + }, } as const; export const contract = c.router(definition); diff --git a/control-plane/src/modules/contract.ts b/control-plane/src/modules/contract.ts index 7bb61faa..e75e09f0 100644 --- a/control-plane/src/modules/contract.ts +++ b/control-plane/src/modules/contract.ts @@ -538,13 +538,7 @@ export const definition = { config: z .object({ id: z.string().describe("DEPRECATED"), - input: z - .object({}) - .passthrough() - .describe( - "DEPRECATED", - ) - .optional(), + input: z.object({}).passthrough().describe("DEPRECATED").optional(), }) .describe("DEPRECATED") .optional(), @@ -1518,6 +1512,22 @@ export const definition = { clusterId: z.string(), }), }, + getServerStats: { + method: "GET", + path: "/stats", + responses: { + 200: z.object({ + functionCalls: z.object({ + count: z.number(), + }), + tokenUsage: z.object({ + input: z.number(), + output: z.number(), + }), + refreshedAt: z.number(), + }), + }, + }, } as const; export const contract = c.router(definition); diff --git a/control-plane/src/modules/router.ts b/control-plane/src/modules/router.ts index 0bbd1f3b..5d661762 100644 --- a/control-plane/src/modules/router.ts +++ b/control-plane/src/modules/router.ts @@ -46,6 +46,7 @@ import { callsRouter } from "./calls/router"; import { buildModel } from "./models"; import { deserializeFunctionSchema } from "./service-definitions"; import { integrationsRouter } from "./integrations/router"; +import { getServerStats } from "./server-stats"; const readFile = util.promisify(fs.readFile); @@ -900,4 +901,12 @@ export const router = initServer().router(contract, { body: result.parsed, }; }, + getServerStats: async () => { + const stats = await getServerStats(); + + return { + status: 200, + body: stats, + }; + }, }); diff --git a/control-plane/src/modules/server-stats.ts b/control-plane/src/modules/server-stats.ts new file mode 100644 index 00000000..0f1951a2 --- /dev/null +++ b/control-plane/src/modules/server-stats.ts @@ -0,0 +1,52 @@ +import { db, events, jobs } from "./data"; +import { eq, sql } from "drizzle-orm"; +import { createCache } from "../utilities/cache"; + +const cache = createCache<{ + functionCalls: { count: number }; + tokenUsage: { input: number; output: number }; + refreshedAt: number; +}>(Symbol("serverStats")); + +export async function getServerStats() { + const cached = await cache.get("server-stats"); + if (cached !== undefined) { + return cached; + } + + const thirtyDaysAgo = new Date(); + thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); + + const [functionCalls] = await db + .select({ + count: sql`count(*)`, + }) + .from(jobs) + .where(sql`created_at >= ${thirtyDaysAgo}`); + + const [tokenUsage] = await db + .select({ + input: sql`sum(token_usage_input)`, + output: sql`sum(token_usage_output)`, + }) + .from(events) + .where(sql`created_at >= ${thirtyDaysAgo}`); + + const [predictions] = await db + .select({ + count: sql`count(*)`, + }) + .from(events) + .where(sql`type = 'modelInvocation' AND created_at >= ${thirtyDaysAgo}`); + + const stats = { + functionCalls, + tokenUsage, + predictions, + refreshedAt: Date.now(), + }; + + // Cache for 10 minutes + await cache.set("server-stats", stats, 1000 * 60 * 10); + return stats; +} From ecc3755589b7e133e1a90854dc3acd5bd08530c5 Mon Sep 17 00:00:00 2001 From: Nadeesha Cabral Date: Fri, 6 Dec 2024 10:30:42 +1100 Subject: [PATCH 2/3] chore: Update contract schemas and add new sync script - Added missing commas in various schema definitions for consistency. - Introduced new endpoints for listing usage activity and getting server stats. - Deprecated certain fields and methods in the contract schemas. - Added a new script `sync-contracts.sh` to synchronize contract files across different directories. - Updated default values for `callSummarization` in the contract definitions. - Introduced new schemas for integrations and structured output handling. --- app/client/contract.ts | 124 ++++++++-------- cli/src/client/contract.ts | 89 +++++++---- scripts/sync-contracts.sh | 32 ++++ sdk-node/src/contract.ts | 29 +++- sdk-react/src/contract.ts | 292 +++++++++++++++++++++++++------------ 5 files changed, 372 insertions(+), 194 deletions(-) create mode 100644 scripts/sync-contracts.sh diff --git a/app/client/contract.ts b/app/client/contract.ts index 1d0927c4..e75e09f0 100644 --- a/app/client/contract.ts +++ b/app/client/contract.ts @@ -48,7 +48,7 @@ export const VersionedTextsSchema = z.object({ z.object({ version: z.string(), content: z.string(), - }) + }), ), }); @@ -88,7 +88,7 @@ export const learningSchema = z.object({ summary: z .string() .describe( - "The new information that was learned. Be generic, do not refer to the entities." + "The new information that was learned. Be generic, do not refer to the entities.", ), entities: z .array( @@ -97,7 +97,7 @@ export const learningSchema = z.object({ .string() .describe("The name of the entity this learning relates to."), type: z.enum(["tool"]), - }) + }), ) .describe("The entities this learning relates to."), relevance: z.object({ @@ -121,7 +121,7 @@ export const agentDataSchema = z toolName: z.string(), reasoning: z.string().optional(), input: z.object({}).passthrough(), - }) + }), ) .optional(), }) @@ -162,7 +162,7 @@ export const definition = { description: z.string().optional(), schema: z.string().optional(), config: FunctionConfigSchema.optional(), - }) + }), ) .optional(), }), @@ -231,7 +231,7 @@ export const definition = { .and( z.object({ data: z.string(), - }) + }), ), }, getContract: { @@ -256,7 +256,7 @@ export const definition = { name: z.string(), createdAt: z.date(), description: z.string().nullable(), - }) + }), ), 401: z.undefined(), }, @@ -332,13 +332,13 @@ export const definition = { name: z.string().optional(), description: z.string().optional(), additionalContext: VersionedTextsSchema.optional().describe( - "Additional cluster context which is included in all runs" + "Additional cluster context which is included in all runs", ), debug: z .boolean() .optional() .describe( - "Enable additional logging (Including prompts and results) for use by Inferable support" + "Enable additional logging (Including prompts and results) for use by Inferable support", ), enableRunConfigs: z.boolean().optional(), enableKnowledgebase: z.boolean().optional(), @@ -389,7 +389,7 @@ export const definition = { workflowId: z.string().nullable(), meta: z.any().nullable(), id: z.string(), - }) + }), ), 401: z.undefined(), 404: z.undefined(), @@ -418,13 +418,13 @@ export const definition = { totalInputTokens: z.number(), totalOutputTokens: z.number(), totalModelInvocations: z.number(), - }) + }), ), agentRuns: z.array( z.object({ date: z.string(), totalAgentRuns: z.number(), - }) + }), ), }), }, @@ -481,23 +481,23 @@ export const definition = { resultSchema: anyObject .optional() .describe( - "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema" + "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema", ), attachedFunctions: z .array(functionReference) .optional() .describe( - "An array of functions to make available to the run. By default all functions in the cluster will be available" + "An array of functions to make available to the run. By default all functions in the cluster will be available", ), onStatusChange: z .object({ function: functionReference.describe( - "A function to call when the run status changes" + "A function to call when the run status changes", ), }) .optional() .describe( - "Mechanism for receiving notifications when the run status changes" + "Mechanism for receiving notifications when the run status changes", ), metadata: z .record(z.string()) @@ -513,28 +513,34 @@ export const definition = { .object({}) .passthrough() .describe("The mock output of the function"), - }) + }), ) .optional() .describe( - "Function mocks to be used in the run. (Keys should be function in the format _)" + "Function mocks to be used in the run. (Keys should be function in the format _)", ), }) .optional() .describe( - "When provided, the run will be marked as as a test / evaluation" + "When provided, the run will be marked as as a test / evaluation", ), + configId: z + .string() + .optional() + .describe("The run configuration ID to use"), + input: z + .object({}) + .passthrough() + .describe( + "Structured input arguments to merge with the initial prompt. The schema must match the run configuration input schema if defined", + ) + .optional(), config: z .object({ - id: z.string().describe("The run configuration ID"), - input: z - .object({}) - .passthrough() - .describe( - "The run configuration input arguments, the schema must match the run configuration input schema" - ) - .optional(), + id: z.string().describe("DEPRECATED"), + input: z.object({}).passthrough().describe("DEPRECATED").optional(), }) + .describe("DEPRECATED") .optional(), context: anyObject .optional() @@ -553,14 +559,14 @@ export const definition = { .describe("Enable reasoning traces"), callSummarization: z .boolean() - .default(true) + .default(false) .optional() .describe("Enable summarization of oversized call results"), interactive: z .boolean() .default(true) .describe( - "Allow the run to be continued with follow-up messages / message edits" + "Allow the run to be continued with follow-up messages / message edits", ), }), responses: { @@ -638,7 +644,7 @@ export const definition = { createdAt: z.date(), pending: z.boolean().default(false), displayableContext: z.record(z.string()).nullable(), - }) + }), ), 401: z.undefined(), }, @@ -676,7 +682,7 @@ export const definition = { configId: z.string().nullable(), configVersion: z.number().nullable(), feedbackScore: z.number().nullable(), - }) + }), ), 401: z.undefined(), }, @@ -756,23 +762,6 @@ export const definition = { messageId: z.string(), }), }, - storeServiceMetadata: { - method: "PUT", - path: "/clusters/:clusterId/services/:service/keys/:key", - headers: z.object({ authorization: z.string() }), - body: z.object({ - value: z.string(), - }), - pathParams: z.object({ - clusterId: z.string(), - service: z.string(), - key: z.string(), - }), - responses: { - 204: z.undefined(), - 401: z.undefined(), - }, - }, getClusterExport: { method: "GET", path: "/clusters/:clusterId/export", @@ -840,7 +829,7 @@ export const definition = { targetFn: z.string(), service: z.string(), executingMachineId: z.string().nullable(), - }) + }), ), }, }, @@ -876,7 +865,7 @@ export const definition = { createdAt: z.date(), createdBy: z.string(), revokedAt: z.date().nullable(), - }) + }), ), }, }, @@ -900,13 +889,16 @@ export const definition = { headers: z.object({ authorization: z.string(), }), + query: z.object({ + limit: z.coerce.number().min(10).max(50).default(50), + }), responses: { 200: z.array( z.object({ id: z.string(), lastPingAt: z.date(), ip: z.string(), - }) + }), ), }, pathParams: z.object({ @@ -932,10 +924,10 @@ export const definition = { description: z.string().optional(), schema: z.string().optional(), config: FunctionConfigSchema.optional(), - }) + }), ) .optional(), - }) + }), ), }, pathParams: z.object({ @@ -974,7 +966,7 @@ export const definition = { createdAt: z.date(), pending: z.boolean().default(false), displayableContext: z.record(z.string()).nullable(), - }) + }), ), activity: z.array( z.object({ @@ -985,7 +977,7 @@ export const definition = { createdAt: z.date(), jobId: z.string().nullable(), targetFn: z.string().nullable(), - }) + }), ), jobs: z.array( z.object({ @@ -997,7 +989,7 @@ export const definition = { createdAt: z.date(), approved: z.boolean().nullable(), approvalRequested: z.boolean().nullable(), - }) + }), ), run: z.object({ id: z.string(), @@ -1111,7 +1103,7 @@ export const definition = { resultSchema: anyObject.nullable(), inputSchema: anyObject.nullable(), public: z.boolean(), - }) + }), ), }), 401: z.undefined(), @@ -1216,7 +1208,7 @@ export const definition = { resultSchema: z.unknown().nullable(), createdAt: z.date(), updatedAt: z.date(), - }) + }), ), 401: z.undefined(), }, @@ -1243,7 +1235,7 @@ export const definition = { createdAt: z.date(), updatedAt: z.date(), similarity: z.number(), - }) + }), ), 401: z.undefined(), }, @@ -1263,7 +1255,7 @@ export const definition = { jobFailureCount: z.number(), timeToCompletion: z.number(), jobCount: z.number(), - }) + }), ), }, pathParams: z.object({ @@ -1284,7 +1276,7 @@ export const definition = { .array(z.string()) .transform((tags) => tags.map((tag) => tag.toLowerCase().trim())), title: z.string(), - }) + }), ), }), responses: { @@ -1312,7 +1304,7 @@ export const definition = { tags: z.array(z.string()), title: z.string(), similarity: z.number(), - }) + }), ), 401: z.undefined(), }, @@ -1363,7 +1355,7 @@ export const definition = { data: z.string(), tags: z.array(z.string()), title: z.string(), - }) + }), ), 401: z.undefined(), }, @@ -1393,7 +1385,7 @@ export const definition = { .max(20) .default(0) .describe( - "Time in seconds to keep the request open waiting for a response" + "Time in seconds to keep the request open waiting for a response", ), }), headers: z.object({ @@ -1471,7 +1463,7 @@ export const definition = { authContext: z.any().nullable(), runContext: z.any().nullable(), approved: z.boolean(), - }) + }), ), }, }, @@ -1503,7 +1495,7 @@ export const definition = { resultSchema: anyObject .optional() .describe( - "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema" + "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema", ), modelId: z.enum(["claude-3-5-sonnet", "claude-3-haiku"]), temperature: z diff --git a/cli/src/client/contract.ts b/cli/src/client/contract.ts index 07aed2fd..e75e09f0 100644 --- a/cli/src/client/contract.ts +++ b/cli/src/client/contract.ts @@ -403,6 +403,35 @@ export const definition = { includeMeta: z.string().optional(), }), }, + listUsageActivity: { + method: "GET", + path: "/clusters/:clusterId/usage", + headers: z.object({ + authorization: z.string(), + }), + responses: { + 200: z.object({ + modelUsage: z.array( + z.object({ + date: z.string(), + modelId: z.string().nullable(), + totalInputTokens: z.number(), + totalOutputTokens: z.number(), + totalModelInvocations: z.number(), + }), + ), + agentRuns: z.array( + z.object({ + date: z.string(), + totalAgentRuns: z.number(), + }), + ), + }), + }, + pathParams: z.object({ + clusterId: z.string(), + }), + }, getEventMeta: { method: "GET", path: "/clusters/:clusterId/events/:eventId/meta", @@ -495,17 +524,23 @@ export const definition = { .describe( "When provided, the run will be marked as as a test / evaluation", ), + configId: z + .string() + .optional() + .describe("The run configuration ID to use"), + input: z + .object({}) + .passthrough() + .describe( + "Structured input arguments to merge with the initial prompt. The schema must match the run configuration input schema if defined", + ) + .optional(), config: z .object({ - id: z.string().describe("The run configuration ID"), - input: z - .object({}) - .passthrough() - .describe( - "The run configuration input arguments, the schema must match the run configuration input schema", - ) - .optional(), + id: z.string().describe("DEPRECATED"), + input: z.object({}).passthrough().describe("DEPRECATED").optional(), }) + .describe("DEPRECATED") .optional(), context: anyObject .optional() @@ -524,7 +559,7 @@ export const definition = { .describe("Enable reasoning traces"), callSummarization: z .boolean() - .default(true) + .default(false) .optional() .describe("Enable summarization of oversized call results"), interactive: z @@ -727,23 +762,6 @@ export const definition = { messageId: z.string(), }), }, - storeServiceMetadata: { - method: "PUT", - path: "/clusters/:clusterId/services/:service/keys/:key", - headers: z.object({ authorization: z.string() }), - body: z.object({ - value: z.string(), - }), - pathParams: z.object({ - clusterId: z.string(), - service: z.string(), - key: z.string(), - }), - responses: { - 204: z.undefined(), - 401: z.undefined(), - }, - }, getClusterExport: { method: "GET", path: "/clusters/:clusterId/export", @@ -871,6 +889,9 @@ export const definition = { headers: z.object({ authorization: z.string(), }), + query: z.object({ + limit: z.coerce.number().min(10).max(50).default(50), + }), responses: { 200: z.array( z.object({ @@ -1491,6 +1512,22 @@ export const definition = { clusterId: z.string(), }), }, + getServerStats: { + method: "GET", + path: "/stats", + responses: { + 200: z.object({ + functionCalls: z.object({ + count: z.number(), + }), + tokenUsage: z.object({ + input: z.number(), + output: z.number(), + }), + refreshedAt: z.number(), + }), + }, + }, } as const; export const contract = c.router(definition); diff --git a/scripts/sync-contracts.sh b/scripts/sync-contracts.sh new file mode 100644 index 00000000..3bb3e699 --- /dev/null +++ b/scripts/sync-contracts.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Find the source contract file +SOURCE_CONTRACT="control-plane/src/modules/contract.ts" + +if [ ! -f "$SOURCE_CONTRACT" ]; then + echo "Error: Source contract file not found at $SOURCE_CONTRACT" + exit 1 +fi + +# Find all contract.ts files recursively, excluding the source file and node_modules +find . -name "contract.ts" -not -path "*/node_modules/*" -not -path "./control-plane/src/modules/contract.ts" | while read -r target_file; do + echo "Syncing contract to: $target_file" + + # Create backup of target file + cp "$target_file" "${target_file}.backup" + + # Copy source contract to target location + cp "$SOURCE_CONTRACT" "$target_file" + + # Check if copy was successful + if [ $? -eq 0 ]; then + echo "Successfully synced contract to: $target_file" + rm "${target_file}.backup" + else + echo "Error syncing contract to: $target_file" + # Restore backup if copy failed + mv "${target_file}.backup" "$target_file" + fi +done + +echo "Contract sync complete" diff --git a/sdk-node/src/contract.ts b/sdk-node/src/contract.ts index 95f875c2..e75e09f0 100644 --- a/sdk-node/src/contract.ts +++ b/sdk-node/src/contract.ts @@ -538,13 +538,7 @@ export const definition = { config: z .object({ id: z.string().describe("DEPRECATED"), - input: z - .object({}) - .passthrough() - .describe( - "DEPRECATED", - ) - .optional(), + input: z.object({}).passthrough().describe("DEPRECATED").optional(), }) .describe("DEPRECATED") .optional(), @@ -565,7 +559,7 @@ export const definition = { .describe("Enable reasoning traces"), callSummarization: z .boolean() - .default(true) + .default(false) .optional() .describe("Enable summarization of oversized call results"), interactive: z @@ -895,6 +889,9 @@ export const definition = { headers: z.object({ authorization: z.string(), }), + query: z.object({ + limit: z.coerce.number().min(10).max(50).default(50), + }), responses: { 200: z.array( z.object({ @@ -1515,6 +1512,22 @@ export const definition = { clusterId: z.string(), }), }, + getServerStats: { + method: "GET", + path: "/stats", + responses: { + 200: z.object({ + functionCalls: z.object({ + count: z.number(), + }), + tokenUsage: z.object({ + input: z.number(), + output: z.number(), + }), + refreshedAt: z.number(), + }), + }, + }, } as const; export const contract = c.router(definition); diff --git a/sdk-react/src/contract.ts b/sdk-react/src/contract.ts index ef49693d..e75e09f0 100644 --- a/sdk-react/src/contract.ts +++ b/sdk-react/src/contract.ts @@ -22,6 +22,12 @@ const functionReference = z.object({ const anyObject = z.object({}).passthrough(); +export const interruptSchema = z.discriminatedUnion("type", [ + z.object({ + type: z.literal("approval"), + }), +]); + export const blobSchema = z.object({ id: z.string(), name: z.string(), @@ -46,6 +52,24 @@ export const VersionedTextsSchema = z.object({ ), }); +export const integrationSchema = z.object({ + toolhouse: z + .object({ + apiKey: z.string(), + }) + .optional() + .nullable(), + langfuse: z + .object({ + publicKey: z.string(), + secretKey: z.string(), + baseUrl: z.string(), + sendMessagePayloads: z.boolean(), + }) + .optional() + .nullable(), +}); + export const genericMessageDataSchema = z .object({ message: z.string(), @@ -118,7 +142,6 @@ export const FunctionConfigSchema = z.object({ .optional(), retryCountOnStall: z.number().optional(), timeoutSeconds: z.number().optional(), - requiresApproval: z.boolean().default(false).optional(), private: z.boolean().default(false).optional(), }); @@ -159,6 +182,26 @@ export const definition = { }), }, }, + createCallApproval: { + method: "POST", + path: "/clusters/:clusterId/calls/:callId/approval", + headers: z.object({ + authorization: z.string(), + }), + pathParams: z.object({ + clusterId: z.string(), + callId: z.string(), + }), + responses: { + 204: z.undefined(), + 404: z.object({ + message: z.string(), + }), + }, + body: z.object({ + approved: z.boolean(), + }), + }, createCallBlob: { method: "POST", path: "/clusters/:clusterId/calls/:callId/blobs", @@ -233,6 +276,37 @@ export const definition = { .describe("Human readable description of the cluster"), }), }, + upsertIntegrations: { + method: "PUT", + path: "/clusters/:clusterId/integrations", + headers: z.object({ + authorization: z.string(), + }), + responses: { + 200: z.undefined(), + 401: z.undefined(), + 400: z.object({ + message: z.string(), + }), + }, + pathParams: z.object({ + clusterId: z.string(), + }), + body: integrationSchema, + }, + getIntegrations: { + method: "GET", + path: "/clusters/:clusterId/integrations", + headers: z.object({ + authorization: z.string(), + }), + responses: { + 200: integrationSchema, + }, + pathParams: z.object({ + clusterId: z.string(), + }), + }, deleteCluster: { method: "DELETE", path: "/clusters/:clusterId", @@ -266,6 +340,8 @@ export const definition = { .describe( "Enable additional logging (Including prompts and results) for use by Inferable support", ), + enableRunConfigs: z.boolean().optional(), + enableKnowledgebase: z.boolean().optional(), }), }, getCluster: { @@ -282,6 +358,8 @@ export const definition = { additionalContext: VersionedTextsSchema.nullable(), createdAt: z.date(), debug: z.boolean(), + enableRunConfigs: z.boolean(), + enableKnowledgebase: z.boolean(), lastPingAt: z.date().nullable(), }), 401: z.undefined(), @@ -325,6 +403,35 @@ export const definition = { includeMeta: z.string().optional(), }), }, + listUsageActivity: { + method: "GET", + path: "/clusters/:clusterId/usage", + headers: z.object({ + authorization: z.string(), + }), + responses: { + 200: z.object({ + modelUsage: z.array( + z.object({ + date: z.string(), + modelId: z.string().nullable(), + totalInputTokens: z.number(), + totalOutputTokens: z.number(), + totalModelInvocations: z.number(), + }), + ), + agentRuns: z.array( + z.object({ + date: z.string(), + totalAgentRuns: z.number(), + }), + ), + }), + }, + pathParams: z.object({ + clusterId: z.string(), + }), + }, getEventMeta: { method: "GET", path: "/clusters/:clusterId/events/:eventId/meta", @@ -368,7 +475,7 @@ export const definition = { .optional() .describe("The name of the run, if not provided it will be generated"), model: z - .enum(["claude-3-5-sonnet", "claude-3-5-sonnet:beta", "claude-3-haiku"]) + .enum(["claude-3-5-sonnet", "claude-3-haiku"]) .optional() .describe("The model identifier for the run"), resultSchema: anyObject @@ -417,18 +524,27 @@ export const definition = { .describe( "When provided, the run will be marked as as a test / evaluation", ), + configId: z + .string() + .optional() + .describe("The run configuration ID to use"), + input: z + .object({}) + .passthrough() + .describe( + "Structured input arguments to merge with the initial prompt. The schema must match the run configuration input schema if defined", + ) + .optional(), config: z .object({ - id: z.string().describe("The run configuration ID"), - input: z - .object({}) - .passthrough() - .describe( - "The run configuration input arguments, the schema must match the run configuration input schema", - ) - .optional(), + id: z.string().describe("DEPRECATED"), + input: z.object({}).passthrough().describe("DEPRECATED").optional(), }) + .describe("DEPRECATED") .optional(), + context: anyObject + .optional() + .describe("Additional context to propogate to all calls in the run"), template: z .object({ id: z.string().describe("DEPRECATED"), @@ -443,7 +559,7 @@ export const definition = { .describe("Enable reasoning traces"), callSummarization: z .boolean() - .default(true) + .default(false) .optional() .describe("Enable summarization of oversized call results"), interactive: z @@ -620,55 +736,6 @@ export const definition = { clusterId: z.string(), }), }, - resolveInputRequest: { - method: "POST", - path: "/clusters/:clusterId/runs/:runId/input-requests/:inputRequestId", - headers: z.object({ - authorization: z.string().optional(), - }), - body: z.object({ - input: z.string(), - }), - responses: { - 204: z.undefined(), - 401: z.undefined(), - 404: z.undefined(), - }, - pathParams: z.object({ - runId: z.string(), - inputRequestId: z.string(), - clusterId: z.string(), - }), - }, - getInputRequest: { - method: "GET", - path: "/clusters/:clusterId/runs/:runId/input-requests/:inputRequestId", - headers: z.object({ - authorization: z.string().optional(), - }), - pathParams: z.object({ - clusterId: z.string(), - runId: z.string(), - inputRequestId: z.string(), - }), - responses: { - 200: z.object({ - id: z.string(), - runId: z.string(), - clusterId: z.string(), - resolvedAt: z.date().nullable(), - createdAt: z.date(), - requestArgs: z.string().nullable(), - service: z.string().nullable(), - function: z.string().nullable(), - description: z.string().nullable(), - type: z.string(), - options: z.array(z.string()).optional(), - }), - 401: z.undefined(), - 404: z.undefined(), - }, - }, oas: { method: "GET", path: "/public/oas.json", @@ -695,23 +762,6 @@ export const definition = { messageId: z.string(), }), }, - storeServiceMetadata: { - method: "PUT", - path: "/clusters/:clusterId/services/:service/keys/:key", - headers: z.object({ authorization: z.string() }), - body: z.object({ - value: z.string(), - }), - pathParams: z.object({ - clusterId: z.string(), - service: z.string(), - key: z.string(), - }), - responses: { - 204: z.undefined(), - 401: z.undefined(), - }, - }, getClusterExport: { method: "GET", path: "/clusters/:clusterId/export", @@ -839,6 +889,9 @@ export const definition = { headers: z.object({ authorization: z.string(), }), + query: z.object({ + limit: z.coerce.number().min(10).max(50).default(50), + }), responses: { 200: z.array( z.object({ @@ -889,7 +942,6 @@ export const definition = { messagesAfter: z.string().default("0"), activityAfter: z.string().default("0"), jobsAfter: z.string().default("0"), - inputRequestsAfter: z.string().default("0"), }), pathParams: z.object({ clusterId: z.string(), @@ -935,19 +987,8 @@ export const definition = { service: z.string(), resultType: z.string().nullable(), createdAt: z.date(), - }), - ), - inputRequests: z.array( - z.object({ - id: z.string(), - type: z.string(), - requestArgs: z.string().nullable().optional(), - resolvedAt: z.date().nullable().optional(), - createdAt: z.date(), - service: z.string().nullable().optional(), - function: z.string().nullable().optional(), - description: z.string().nullable().optional(), - presentedOptions: z.array(z.string()).nullable().optional(), + approved: z.boolean().nullable(), + approvalRequested: z.boolean().nullable(), }), ), run: z.object({ @@ -1303,6 +1344,25 @@ export const definition = { 401: z.undefined(), }, }, + getAllKnowledgeArtifacts: { + method: "GET", + path: "/clusters/:clusterId/knowledge-export", + headers: z.object({ authorization: z.string() }), + responses: { + 200: z.array( + z.object({ + id: z.string(), + data: z.string(), + tags: z.array(z.string()), + title: z.string(), + }), + ), + 401: z.undefined(), + }, + pathParams: z.object({ + clusterId: z.string(), + }), + }, createRunRetry: { method: "POST", path: "/clusters/:clusterId/runs/:runId/retry", @@ -1341,7 +1401,7 @@ export const definition = { 200: z.object({ id: z.string(), result: z.any().nullable(), - resultType: z.enum(["resolution", "rejection"]).nullable(), + resultType: z.enum(["resolution", "rejection", "interrupt"]).nullable(), status: z.enum(["pending", "running", "success", "failure", "stalled"]), }), }, @@ -1363,7 +1423,7 @@ export const definition = { }, body: z.object({ result: z.any(), - resultType: z.enum(["resolution", "rejection"]), + resultType: z.enum(["resolution", "rejection", "interrupt"]), meta: z.object({ functionExecutionTime: z.number().optional(), }), @@ -1400,7 +1460,9 @@ export const definition = { id: z.string(), function: z.string(), input: z.any(), - customerAuthContext: z.any().nullable(), + authContext: z.any().nullable(), + runContext: z.any().nullable(), + approved: z.boolean(), }), ), }, @@ -1424,6 +1486,48 @@ export const definition = { artifactId: z.string(), }), }, + createStructuredOutput: { + method: "POST", + path: "/clusters/:clusterId/structured-output", + headers: z.object({ authorization: z.string() }), + body: z.object({ + prompt: z.string(), + resultSchema: anyObject + .optional() + .describe( + "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema", + ), + modelId: z.enum(["claude-3-5-sonnet", "claude-3-haiku"]), + temperature: z + .number() + .optional() + .describe("The temperature to use for the model") + .default(0.5), + }), + responses: { + 200: z.unknown(), + 401: z.undefined(), + }, + pathParams: z.object({ + clusterId: z.string(), + }), + }, + getServerStats: { + method: "GET", + path: "/stats", + responses: { + 200: z.object({ + functionCalls: z.object({ + count: z.number(), + }), + tokenUsage: z.object({ + input: z.number(), + output: z.number(), + }), + refreshedAt: z.number(), + }), + }, + }, } as const; export const contract = c.router(definition); From fcd760ac7207379fa5b09c75fb414709970a7338 Mon Sep 17 00:00:00 2001 From: Nadeesha Cabral Date: Sat, 7 Dec 2024 16:45:40 +1100 Subject: [PATCH 3/3] Revert "chore: Update contract schemas and add new sync script" This reverts commit ecc3755589b7e133e1a90854dc3acd5bd08530c5. --- app/client/contract.ts | 124 ++++++++-------- cli/src/client/contract.ts | 89 ++++------- scripts/sync-contracts.sh | 32 ---- sdk-node/src/contract.ts | 29 +--- sdk-react/src/contract.ts | 292 ++++++++++++------------------------- 5 files changed, 194 insertions(+), 372 deletions(-) delete mode 100644 scripts/sync-contracts.sh diff --git a/app/client/contract.ts b/app/client/contract.ts index e75e09f0..1d0927c4 100644 --- a/app/client/contract.ts +++ b/app/client/contract.ts @@ -48,7 +48,7 @@ export const VersionedTextsSchema = z.object({ z.object({ version: z.string(), content: z.string(), - }), + }) ), }); @@ -88,7 +88,7 @@ export const learningSchema = z.object({ summary: z .string() .describe( - "The new information that was learned. Be generic, do not refer to the entities.", + "The new information that was learned. Be generic, do not refer to the entities." ), entities: z .array( @@ -97,7 +97,7 @@ export const learningSchema = z.object({ .string() .describe("The name of the entity this learning relates to."), type: z.enum(["tool"]), - }), + }) ) .describe("The entities this learning relates to."), relevance: z.object({ @@ -121,7 +121,7 @@ export const agentDataSchema = z toolName: z.string(), reasoning: z.string().optional(), input: z.object({}).passthrough(), - }), + }) ) .optional(), }) @@ -162,7 +162,7 @@ export const definition = { description: z.string().optional(), schema: z.string().optional(), config: FunctionConfigSchema.optional(), - }), + }) ) .optional(), }), @@ -231,7 +231,7 @@ export const definition = { .and( z.object({ data: z.string(), - }), + }) ), }, getContract: { @@ -256,7 +256,7 @@ export const definition = { name: z.string(), createdAt: z.date(), description: z.string().nullable(), - }), + }) ), 401: z.undefined(), }, @@ -332,13 +332,13 @@ export const definition = { name: z.string().optional(), description: z.string().optional(), additionalContext: VersionedTextsSchema.optional().describe( - "Additional cluster context which is included in all runs", + "Additional cluster context which is included in all runs" ), debug: z .boolean() .optional() .describe( - "Enable additional logging (Including prompts and results) for use by Inferable support", + "Enable additional logging (Including prompts and results) for use by Inferable support" ), enableRunConfigs: z.boolean().optional(), enableKnowledgebase: z.boolean().optional(), @@ -389,7 +389,7 @@ export const definition = { workflowId: z.string().nullable(), meta: z.any().nullable(), id: z.string(), - }), + }) ), 401: z.undefined(), 404: z.undefined(), @@ -418,13 +418,13 @@ export const definition = { totalInputTokens: z.number(), totalOutputTokens: z.number(), totalModelInvocations: z.number(), - }), + }) ), agentRuns: z.array( z.object({ date: z.string(), totalAgentRuns: z.number(), - }), + }) ), }), }, @@ -481,23 +481,23 @@ export const definition = { resultSchema: anyObject .optional() .describe( - "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema", + "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema" ), attachedFunctions: z .array(functionReference) .optional() .describe( - "An array of functions to make available to the run. By default all functions in the cluster will be available", + "An array of functions to make available to the run. By default all functions in the cluster will be available" ), onStatusChange: z .object({ function: functionReference.describe( - "A function to call when the run status changes", + "A function to call when the run status changes" ), }) .optional() .describe( - "Mechanism for receiving notifications when the run status changes", + "Mechanism for receiving notifications when the run status changes" ), metadata: z .record(z.string()) @@ -513,34 +513,28 @@ export const definition = { .object({}) .passthrough() .describe("The mock output of the function"), - }), + }) ) .optional() .describe( - "Function mocks to be used in the run. (Keys should be function in the format _)", + "Function mocks to be used in the run. (Keys should be function in the format _)" ), }) .optional() .describe( - "When provided, the run will be marked as as a test / evaluation", + "When provided, the run will be marked as as a test / evaluation" ), - configId: z - .string() - .optional() - .describe("The run configuration ID to use"), - input: z - .object({}) - .passthrough() - .describe( - "Structured input arguments to merge with the initial prompt. The schema must match the run configuration input schema if defined", - ) - .optional(), config: z .object({ - id: z.string().describe("DEPRECATED"), - input: z.object({}).passthrough().describe("DEPRECATED").optional(), + id: z.string().describe("The run configuration ID"), + input: z + .object({}) + .passthrough() + .describe( + "The run configuration input arguments, the schema must match the run configuration input schema" + ) + .optional(), }) - .describe("DEPRECATED") .optional(), context: anyObject .optional() @@ -559,14 +553,14 @@ export const definition = { .describe("Enable reasoning traces"), callSummarization: z .boolean() - .default(false) + .default(true) .optional() .describe("Enable summarization of oversized call results"), interactive: z .boolean() .default(true) .describe( - "Allow the run to be continued with follow-up messages / message edits", + "Allow the run to be continued with follow-up messages / message edits" ), }), responses: { @@ -644,7 +638,7 @@ export const definition = { createdAt: z.date(), pending: z.boolean().default(false), displayableContext: z.record(z.string()).nullable(), - }), + }) ), 401: z.undefined(), }, @@ -682,7 +676,7 @@ export const definition = { configId: z.string().nullable(), configVersion: z.number().nullable(), feedbackScore: z.number().nullable(), - }), + }) ), 401: z.undefined(), }, @@ -762,6 +756,23 @@ export const definition = { messageId: z.string(), }), }, + storeServiceMetadata: { + method: "PUT", + path: "/clusters/:clusterId/services/:service/keys/:key", + headers: z.object({ authorization: z.string() }), + body: z.object({ + value: z.string(), + }), + pathParams: z.object({ + clusterId: z.string(), + service: z.string(), + key: z.string(), + }), + responses: { + 204: z.undefined(), + 401: z.undefined(), + }, + }, getClusterExport: { method: "GET", path: "/clusters/:clusterId/export", @@ -829,7 +840,7 @@ export const definition = { targetFn: z.string(), service: z.string(), executingMachineId: z.string().nullable(), - }), + }) ), }, }, @@ -865,7 +876,7 @@ export const definition = { createdAt: z.date(), createdBy: z.string(), revokedAt: z.date().nullable(), - }), + }) ), }, }, @@ -889,16 +900,13 @@ export const definition = { headers: z.object({ authorization: z.string(), }), - query: z.object({ - limit: z.coerce.number().min(10).max(50).default(50), - }), responses: { 200: z.array( z.object({ id: z.string(), lastPingAt: z.date(), ip: z.string(), - }), + }) ), }, pathParams: z.object({ @@ -924,10 +932,10 @@ export const definition = { description: z.string().optional(), schema: z.string().optional(), config: FunctionConfigSchema.optional(), - }), + }) ) .optional(), - }), + }) ), }, pathParams: z.object({ @@ -966,7 +974,7 @@ export const definition = { createdAt: z.date(), pending: z.boolean().default(false), displayableContext: z.record(z.string()).nullable(), - }), + }) ), activity: z.array( z.object({ @@ -977,7 +985,7 @@ export const definition = { createdAt: z.date(), jobId: z.string().nullable(), targetFn: z.string().nullable(), - }), + }) ), jobs: z.array( z.object({ @@ -989,7 +997,7 @@ export const definition = { createdAt: z.date(), approved: z.boolean().nullable(), approvalRequested: z.boolean().nullable(), - }), + }) ), run: z.object({ id: z.string(), @@ -1103,7 +1111,7 @@ export const definition = { resultSchema: anyObject.nullable(), inputSchema: anyObject.nullable(), public: z.boolean(), - }), + }) ), }), 401: z.undefined(), @@ -1208,7 +1216,7 @@ export const definition = { resultSchema: z.unknown().nullable(), createdAt: z.date(), updatedAt: z.date(), - }), + }) ), 401: z.undefined(), }, @@ -1235,7 +1243,7 @@ export const definition = { createdAt: z.date(), updatedAt: z.date(), similarity: z.number(), - }), + }) ), 401: z.undefined(), }, @@ -1255,7 +1263,7 @@ export const definition = { jobFailureCount: z.number(), timeToCompletion: z.number(), jobCount: z.number(), - }), + }) ), }, pathParams: z.object({ @@ -1276,7 +1284,7 @@ export const definition = { .array(z.string()) .transform((tags) => tags.map((tag) => tag.toLowerCase().trim())), title: z.string(), - }), + }) ), }), responses: { @@ -1304,7 +1312,7 @@ export const definition = { tags: z.array(z.string()), title: z.string(), similarity: z.number(), - }), + }) ), 401: z.undefined(), }, @@ -1355,7 +1363,7 @@ export const definition = { data: z.string(), tags: z.array(z.string()), title: z.string(), - }), + }) ), 401: z.undefined(), }, @@ -1385,7 +1393,7 @@ export const definition = { .max(20) .default(0) .describe( - "Time in seconds to keep the request open waiting for a response", + "Time in seconds to keep the request open waiting for a response" ), }), headers: z.object({ @@ -1463,7 +1471,7 @@ export const definition = { authContext: z.any().nullable(), runContext: z.any().nullable(), approved: z.boolean(), - }), + }) ), }, }, @@ -1495,7 +1503,7 @@ export const definition = { resultSchema: anyObject .optional() .describe( - "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema", + "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema" ), modelId: z.enum(["claude-3-5-sonnet", "claude-3-haiku"]), temperature: z diff --git a/cli/src/client/contract.ts b/cli/src/client/contract.ts index e75e09f0..07aed2fd 100644 --- a/cli/src/client/contract.ts +++ b/cli/src/client/contract.ts @@ -403,35 +403,6 @@ export const definition = { includeMeta: z.string().optional(), }), }, - listUsageActivity: { - method: "GET", - path: "/clusters/:clusterId/usage", - headers: z.object({ - authorization: z.string(), - }), - responses: { - 200: z.object({ - modelUsage: z.array( - z.object({ - date: z.string(), - modelId: z.string().nullable(), - totalInputTokens: z.number(), - totalOutputTokens: z.number(), - totalModelInvocations: z.number(), - }), - ), - agentRuns: z.array( - z.object({ - date: z.string(), - totalAgentRuns: z.number(), - }), - ), - }), - }, - pathParams: z.object({ - clusterId: z.string(), - }), - }, getEventMeta: { method: "GET", path: "/clusters/:clusterId/events/:eventId/meta", @@ -524,23 +495,17 @@ export const definition = { .describe( "When provided, the run will be marked as as a test / evaluation", ), - configId: z - .string() - .optional() - .describe("The run configuration ID to use"), - input: z - .object({}) - .passthrough() - .describe( - "Structured input arguments to merge with the initial prompt. The schema must match the run configuration input schema if defined", - ) - .optional(), config: z .object({ - id: z.string().describe("DEPRECATED"), - input: z.object({}).passthrough().describe("DEPRECATED").optional(), + id: z.string().describe("The run configuration ID"), + input: z + .object({}) + .passthrough() + .describe( + "The run configuration input arguments, the schema must match the run configuration input schema", + ) + .optional(), }) - .describe("DEPRECATED") .optional(), context: anyObject .optional() @@ -559,7 +524,7 @@ export const definition = { .describe("Enable reasoning traces"), callSummarization: z .boolean() - .default(false) + .default(true) .optional() .describe("Enable summarization of oversized call results"), interactive: z @@ -762,6 +727,23 @@ export const definition = { messageId: z.string(), }), }, + storeServiceMetadata: { + method: "PUT", + path: "/clusters/:clusterId/services/:service/keys/:key", + headers: z.object({ authorization: z.string() }), + body: z.object({ + value: z.string(), + }), + pathParams: z.object({ + clusterId: z.string(), + service: z.string(), + key: z.string(), + }), + responses: { + 204: z.undefined(), + 401: z.undefined(), + }, + }, getClusterExport: { method: "GET", path: "/clusters/:clusterId/export", @@ -889,9 +871,6 @@ export const definition = { headers: z.object({ authorization: z.string(), }), - query: z.object({ - limit: z.coerce.number().min(10).max(50).default(50), - }), responses: { 200: z.array( z.object({ @@ -1512,22 +1491,6 @@ export const definition = { clusterId: z.string(), }), }, - getServerStats: { - method: "GET", - path: "/stats", - responses: { - 200: z.object({ - functionCalls: z.object({ - count: z.number(), - }), - tokenUsage: z.object({ - input: z.number(), - output: z.number(), - }), - refreshedAt: z.number(), - }), - }, - }, } as const; export const contract = c.router(definition); diff --git a/scripts/sync-contracts.sh b/scripts/sync-contracts.sh deleted file mode 100644 index 3bb3e699..00000000 --- a/scripts/sync-contracts.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# Find the source contract file -SOURCE_CONTRACT="control-plane/src/modules/contract.ts" - -if [ ! -f "$SOURCE_CONTRACT" ]; then - echo "Error: Source contract file not found at $SOURCE_CONTRACT" - exit 1 -fi - -# Find all contract.ts files recursively, excluding the source file and node_modules -find . -name "contract.ts" -not -path "*/node_modules/*" -not -path "./control-plane/src/modules/contract.ts" | while read -r target_file; do - echo "Syncing contract to: $target_file" - - # Create backup of target file - cp "$target_file" "${target_file}.backup" - - # Copy source contract to target location - cp "$SOURCE_CONTRACT" "$target_file" - - # Check if copy was successful - if [ $? -eq 0 ]; then - echo "Successfully synced contract to: $target_file" - rm "${target_file}.backup" - else - echo "Error syncing contract to: $target_file" - # Restore backup if copy failed - mv "${target_file}.backup" "$target_file" - fi -done - -echo "Contract sync complete" diff --git a/sdk-node/src/contract.ts b/sdk-node/src/contract.ts index e75e09f0..95f875c2 100644 --- a/sdk-node/src/contract.ts +++ b/sdk-node/src/contract.ts @@ -538,7 +538,13 @@ export const definition = { config: z .object({ id: z.string().describe("DEPRECATED"), - input: z.object({}).passthrough().describe("DEPRECATED").optional(), + input: z + .object({}) + .passthrough() + .describe( + "DEPRECATED", + ) + .optional(), }) .describe("DEPRECATED") .optional(), @@ -559,7 +565,7 @@ export const definition = { .describe("Enable reasoning traces"), callSummarization: z .boolean() - .default(false) + .default(true) .optional() .describe("Enable summarization of oversized call results"), interactive: z @@ -889,9 +895,6 @@ export const definition = { headers: z.object({ authorization: z.string(), }), - query: z.object({ - limit: z.coerce.number().min(10).max(50).default(50), - }), responses: { 200: z.array( z.object({ @@ -1512,22 +1515,6 @@ export const definition = { clusterId: z.string(), }), }, - getServerStats: { - method: "GET", - path: "/stats", - responses: { - 200: z.object({ - functionCalls: z.object({ - count: z.number(), - }), - tokenUsage: z.object({ - input: z.number(), - output: z.number(), - }), - refreshedAt: z.number(), - }), - }, - }, } as const; export const contract = c.router(definition); diff --git a/sdk-react/src/contract.ts b/sdk-react/src/contract.ts index e75e09f0..ef49693d 100644 --- a/sdk-react/src/contract.ts +++ b/sdk-react/src/contract.ts @@ -22,12 +22,6 @@ const functionReference = z.object({ const anyObject = z.object({}).passthrough(); -export const interruptSchema = z.discriminatedUnion("type", [ - z.object({ - type: z.literal("approval"), - }), -]); - export const blobSchema = z.object({ id: z.string(), name: z.string(), @@ -52,24 +46,6 @@ export const VersionedTextsSchema = z.object({ ), }); -export const integrationSchema = z.object({ - toolhouse: z - .object({ - apiKey: z.string(), - }) - .optional() - .nullable(), - langfuse: z - .object({ - publicKey: z.string(), - secretKey: z.string(), - baseUrl: z.string(), - sendMessagePayloads: z.boolean(), - }) - .optional() - .nullable(), -}); - export const genericMessageDataSchema = z .object({ message: z.string(), @@ -142,6 +118,7 @@ export const FunctionConfigSchema = z.object({ .optional(), retryCountOnStall: z.number().optional(), timeoutSeconds: z.number().optional(), + requiresApproval: z.boolean().default(false).optional(), private: z.boolean().default(false).optional(), }); @@ -182,26 +159,6 @@ export const definition = { }), }, }, - createCallApproval: { - method: "POST", - path: "/clusters/:clusterId/calls/:callId/approval", - headers: z.object({ - authorization: z.string(), - }), - pathParams: z.object({ - clusterId: z.string(), - callId: z.string(), - }), - responses: { - 204: z.undefined(), - 404: z.object({ - message: z.string(), - }), - }, - body: z.object({ - approved: z.boolean(), - }), - }, createCallBlob: { method: "POST", path: "/clusters/:clusterId/calls/:callId/blobs", @@ -276,37 +233,6 @@ export const definition = { .describe("Human readable description of the cluster"), }), }, - upsertIntegrations: { - method: "PUT", - path: "/clusters/:clusterId/integrations", - headers: z.object({ - authorization: z.string(), - }), - responses: { - 200: z.undefined(), - 401: z.undefined(), - 400: z.object({ - message: z.string(), - }), - }, - pathParams: z.object({ - clusterId: z.string(), - }), - body: integrationSchema, - }, - getIntegrations: { - method: "GET", - path: "/clusters/:clusterId/integrations", - headers: z.object({ - authorization: z.string(), - }), - responses: { - 200: integrationSchema, - }, - pathParams: z.object({ - clusterId: z.string(), - }), - }, deleteCluster: { method: "DELETE", path: "/clusters/:clusterId", @@ -340,8 +266,6 @@ export const definition = { .describe( "Enable additional logging (Including prompts and results) for use by Inferable support", ), - enableRunConfigs: z.boolean().optional(), - enableKnowledgebase: z.boolean().optional(), }), }, getCluster: { @@ -358,8 +282,6 @@ export const definition = { additionalContext: VersionedTextsSchema.nullable(), createdAt: z.date(), debug: z.boolean(), - enableRunConfigs: z.boolean(), - enableKnowledgebase: z.boolean(), lastPingAt: z.date().nullable(), }), 401: z.undefined(), @@ -403,35 +325,6 @@ export const definition = { includeMeta: z.string().optional(), }), }, - listUsageActivity: { - method: "GET", - path: "/clusters/:clusterId/usage", - headers: z.object({ - authorization: z.string(), - }), - responses: { - 200: z.object({ - modelUsage: z.array( - z.object({ - date: z.string(), - modelId: z.string().nullable(), - totalInputTokens: z.number(), - totalOutputTokens: z.number(), - totalModelInvocations: z.number(), - }), - ), - agentRuns: z.array( - z.object({ - date: z.string(), - totalAgentRuns: z.number(), - }), - ), - }), - }, - pathParams: z.object({ - clusterId: z.string(), - }), - }, getEventMeta: { method: "GET", path: "/clusters/:clusterId/events/:eventId/meta", @@ -475,7 +368,7 @@ export const definition = { .optional() .describe("The name of the run, if not provided it will be generated"), model: z - .enum(["claude-3-5-sonnet", "claude-3-haiku"]) + .enum(["claude-3-5-sonnet", "claude-3-5-sonnet:beta", "claude-3-haiku"]) .optional() .describe("The model identifier for the run"), resultSchema: anyObject @@ -524,27 +417,18 @@ export const definition = { .describe( "When provided, the run will be marked as as a test / evaluation", ), - configId: z - .string() - .optional() - .describe("The run configuration ID to use"), - input: z - .object({}) - .passthrough() - .describe( - "Structured input arguments to merge with the initial prompt. The schema must match the run configuration input schema if defined", - ) - .optional(), config: z .object({ - id: z.string().describe("DEPRECATED"), - input: z.object({}).passthrough().describe("DEPRECATED").optional(), + id: z.string().describe("The run configuration ID"), + input: z + .object({}) + .passthrough() + .describe( + "The run configuration input arguments, the schema must match the run configuration input schema", + ) + .optional(), }) - .describe("DEPRECATED") .optional(), - context: anyObject - .optional() - .describe("Additional context to propogate to all calls in the run"), template: z .object({ id: z.string().describe("DEPRECATED"), @@ -559,7 +443,7 @@ export const definition = { .describe("Enable reasoning traces"), callSummarization: z .boolean() - .default(false) + .default(true) .optional() .describe("Enable summarization of oversized call results"), interactive: z @@ -736,6 +620,55 @@ export const definition = { clusterId: z.string(), }), }, + resolveInputRequest: { + method: "POST", + path: "/clusters/:clusterId/runs/:runId/input-requests/:inputRequestId", + headers: z.object({ + authorization: z.string().optional(), + }), + body: z.object({ + input: z.string(), + }), + responses: { + 204: z.undefined(), + 401: z.undefined(), + 404: z.undefined(), + }, + pathParams: z.object({ + runId: z.string(), + inputRequestId: z.string(), + clusterId: z.string(), + }), + }, + getInputRequest: { + method: "GET", + path: "/clusters/:clusterId/runs/:runId/input-requests/:inputRequestId", + headers: z.object({ + authorization: z.string().optional(), + }), + pathParams: z.object({ + clusterId: z.string(), + runId: z.string(), + inputRequestId: z.string(), + }), + responses: { + 200: z.object({ + id: z.string(), + runId: z.string(), + clusterId: z.string(), + resolvedAt: z.date().nullable(), + createdAt: z.date(), + requestArgs: z.string().nullable(), + service: z.string().nullable(), + function: z.string().nullable(), + description: z.string().nullable(), + type: z.string(), + options: z.array(z.string()).optional(), + }), + 401: z.undefined(), + 404: z.undefined(), + }, + }, oas: { method: "GET", path: "/public/oas.json", @@ -762,6 +695,23 @@ export const definition = { messageId: z.string(), }), }, + storeServiceMetadata: { + method: "PUT", + path: "/clusters/:clusterId/services/:service/keys/:key", + headers: z.object({ authorization: z.string() }), + body: z.object({ + value: z.string(), + }), + pathParams: z.object({ + clusterId: z.string(), + service: z.string(), + key: z.string(), + }), + responses: { + 204: z.undefined(), + 401: z.undefined(), + }, + }, getClusterExport: { method: "GET", path: "/clusters/:clusterId/export", @@ -889,9 +839,6 @@ export const definition = { headers: z.object({ authorization: z.string(), }), - query: z.object({ - limit: z.coerce.number().min(10).max(50).default(50), - }), responses: { 200: z.array( z.object({ @@ -942,6 +889,7 @@ export const definition = { messagesAfter: z.string().default("0"), activityAfter: z.string().default("0"), jobsAfter: z.string().default("0"), + inputRequestsAfter: z.string().default("0"), }), pathParams: z.object({ clusterId: z.string(), @@ -987,8 +935,19 @@ export const definition = { service: z.string(), resultType: z.string().nullable(), createdAt: z.date(), - approved: z.boolean().nullable(), - approvalRequested: z.boolean().nullable(), + }), + ), + inputRequests: z.array( + z.object({ + id: z.string(), + type: z.string(), + requestArgs: z.string().nullable().optional(), + resolvedAt: z.date().nullable().optional(), + createdAt: z.date(), + service: z.string().nullable().optional(), + function: z.string().nullable().optional(), + description: z.string().nullable().optional(), + presentedOptions: z.array(z.string()).nullable().optional(), }), ), run: z.object({ @@ -1344,25 +1303,6 @@ export const definition = { 401: z.undefined(), }, }, - getAllKnowledgeArtifacts: { - method: "GET", - path: "/clusters/:clusterId/knowledge-export", - headers: z.object({ authorization: z.string() }), - responses: { - 200: z.array( - z.object({ - id: z.string(), - data: z.string(), - tags: z.array(z.string()), - title: z.string(), - }), - ), - 401: z.undefined(), - }, - pathParams: z.object({ - clusterId: z.string(), - }), - }, createRunRetry: { method: "POST", path: "/clusters/:clusterId/runs/:runId/retry", @@ -1401,7 +1341,7 @@ export const definition = { 200: z.object({ id: z.string(), result: z.any().nullable(), - resultType: z.enum(["resolution", "rejection", "interrupt"]).nullable(), + resultType: z.enum(["resolution", "rejection"]).nullable(), status: z.enum(["pending", "running", "success", "failure", "stalled"]), }), }, @@ -1423,7 +1363,7 @@ export const definition = { }, body: z.object({ result: z.any(), - resultType: z.enum(["resolution", "rejection", "interrupt"]), + resultType: z.enum(["resolution", "rejection"]), meta: z.object({ functionExecutionTime: z.number().optional(), }), @@ -1460,9 +1400,7 @@ export const definition = { id: z.string(), function: z.string(), input: z.any(), - authContext: z.any().nullable(), - runContext: z.any().nullable(), - approved: z.boolean(), + customerAuthContext: z.any().nullable(), }), ), }, @@ -1486,48 +1424,6 @@ export const definition = { artifactId: z.string(), }), }, - createStructuredOutput: { - method: "POST", - path: "/clusters/:clusterId/structured-output", - headers: z.object({ authorization: z.string() }), - body: z.object({ - prompt: z.string(), - resultSchema: anyObject - .optional() - .describe( - "A JSON schema definition which the result object should conform to. By default the result will be a JSON object which does not conform to any schema", - ), - modelId: z.enum(["claude-3-5-sonnet", "claude-3-haiku"]), - temperature: z - .number() - .optional() - .describe("The temperature to use for the model") - .default(0.5), - }), - responses: { - 200: z.unknown(), - 401: z.undefined(), - }, - pathParams: z.object({ - clusterId: z.string(), - }), - }, - getServerStats: { - method: "GET", - path: "/stats", - responses: { - 200: z.object({ - functionCalls: z.object({ - count: z.number(), - }), - tokenUsage: z.object({ - input: z.number(), - output: z.number(), - }), - refreshedAt: z.number(), - }), - }, - }, } as const; export const contract = c.router(definition);