Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"typescript": "5.4.5"
},
"dependencies": {
"@formula-monks/kurt": "workspace:*",
"@formula-monks/kurt": "1.5.0",
"@formula-monks/kurt-cache": "workspace:*",
"@formula-monks/kurt-open-ai": "workspace:*",
"@formula-monks/kurt-vertex-ai": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion packages/kurt-cache/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"extends": "semantic-release-monorepo"
},
"dependencies": {
"@formula-monks/kurt": "^1.5.0",
"@formula-monks/kurt": "1.5.0",
"yaml": "^2.4.5",
"zod-to-json-schema": "^3.23.3"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/kurt-open-ai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"extends": "semantic-release-monorepo"
},
"dependencies": {
"@formula-monks/kurt": "^1.5.0",
"@formula-monks/kurt": "1.5.0",
"openai": "4.85.1",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/kurt-vertex-ai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"extends": "semantic-release-monorepo"
},
"dependencies": {
"@formula-monks/kurt": "^1.5.0",
"@formula-monks/kurt": "1.5.0",
"@google-cloud/vertexai": "1.9.3",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.3"
Expand Down
8 changes: 4 additions & 4 deletions packages/kurt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@formula-monks/kurt",
"description": "A wrapper for AI SDKs, for building LLM-agnostic structured AI applications",
"license": "MIT",
"version": "1.5.0",
"version": "1.6.0",
"homepage": "https://github.com/FormulaMonks/kurt",
"repository": {
"type": "git",
Expand All @@ -17,7 +17,7 @@
"build": "tsc --build",
"prepack": "pnpm run build",
"format": "pnpm biome format --write .",
"lint": "pnpm biome lint --apply .",
"lint": "pnpm biome lint --write .",
"check": "pnpm biome check .",
"prepublish": "../../scripts/interpolate-example-code.sh README.md",
"release": "pnpm exec semantic-release"
Expand All @@ -37,9 +37,9 @@
"ts-jest": "^29.1.2",
"type-fest": "^4.18.1",
"typescript": "^5.4.5",
"zod-to-json-schema": "^3.23.3"
"zod-to-json-schema": "^3.24.5"
},
"dependencies": {
"zod": "^3.23.8"
"zod": "^3.24.2"
}
}
41 changes: 23 additions & 18 deletions packages/kurt/spec/FakeAdapterV1.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import type { KurtSamplingOptions, KurtMessage } from "../src/Kurt"
import type { KurtAdapterV1 } from "../src/KurtAdapter"
import type { KurtStreamEvent } from "../src/KurtStream"
import type {
KurtAdapterV1,
KurtSchema,
KurtSchemaInner,
KurtSchemaInnerMap,
KurtSchemaMap,
KurtSchemaMapSingleResult,
KurtSchemaResult,
} from "../src/KurtSchema"
KurtStreamEvent,
RawToolInput,
} from "../src"
import { type KurtMessage, type KurtSamplingOptions, KurtTools } from "../src"

export type FakeMessage = { fake: KurtMessage }
export type FakeSchema = { fake: object }
export type FakeTool = {
fake: { name: string; description: string; parameters: FakeSchema }
}
export type FakeEvent = { fake: KurtStreamEvent<unknown> }
export class FakeAdapterV1
implements
KurtAdapterV1<{
rawMessage: FakeMessage
rawSchema: FakeSchema
rawTool: FakeTool
rawEvent: FakeEvent
}>
{
type FakeAdapterTypeParams = {
rawMessage: FakeMessage
rawSchema: FakeSchema
rawTool: FakeTool
rawEvent: FakeEvent
}

export class FakeAdapterV1 implements KurtAdapterV1<FakeAdapterTypeParams> {
kurtAdapterVersion = "v1" as const

// Hook-in points for testing.
Expand All @@ -39,11 +39,16 @@ export class FakeAdapterV1
return { fake: schema }
}

transformToRawTool(tool: {
name: string
description: string
parameters: { fake: object }
}) {
transformToRawTool(tool: RawToolInput<FakeAdapterTypeParams>): FakeTool {
if (KurtTools.isKurtTool(tool)) {
return {
fake: {
name: tool.type,
description: "Kurt tool",
parameters: { fake: {} },
},
}
}
return { fake: tool }
}

Expand Down
2 changes: 1 addition & 1 deletion packages/kurt/spec/Kurt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
type KurtCreateOptions,
type KurtSamplingOptions,
KurtSamplingOptionsDefault,
} from "../src/Kurt"
} from "../src"

function createV1(options: KurtCreateOptions = {}) {
const adapter = new FakeAdapterV1()
Expand Down
2 changes: 1 addition & 1 deletion packages/kurt/spec/KurtSchema.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, test } from "@jest/globals"
import { KurtSchema } from "../src/KurtSchema"
import { KurtSchema } from "../src"
import { zodToJsonSchema } from "zod-to-json-schema"
import type { JSONSchema7 } from "json-schema"

Expand Down
2 changes: 1 addition & 1 deletion packages/kurt/spec/KurtStream.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, test } from "@jest/globals"
import { z } from "zod"
import { KurtStream, type KurtStreamEvent } from "../src/KurtStream"
import { KurtStream, type KurtStreamEvent } from "../src"

function kurtSayHelloEvents() {
return [
Expand Down
39 changes: 39 additions & 0 deletions packages/kurt/spec/KurtTools.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { describe, expect, it } from "@jest/globals"
import { KurtTools } from "../src"

describe("KurtTools.isKurtTool", () => {
it("should return true for tools created via KurtTools factory methods", () => {
const webSearchTool = KurtTools.WebSearch()
expect(KurtTools.isKurtTool(webSearchTool)).toBe(true)
})

it("should create new instances each time a factory method is called", () => {
const tool1 = KurtTools.WebSearch()
const tool2 = KurtTools.WebSearch()

expect(tool1).not.toBe(tool2) // Different instances
expect(tool1).toEqual(tool2) // But equivalent in structure
})

it("should return false for objects that look like KurtTools but are not instances", () => {
const fakeTool = { type: "web_search" }
expect(KurtTools.isKurtTool(fakeTool)).toBe(false)
})

it("should return false for primitive values", () => {
expect(KurtTools.isKurtTool(null)).toBe(false)
expect(KurtTools.isKurtTool(undefined)).toBe(false)
expect(KurtTools.isKurtTool(42)).toBe(false)
expect(KurtTools.isKurtTool("string")).toBe(false)
expect(KurtTools.isKurtTool(true)).toBe(false)
})

it("should return false for objects that are not KurtTools", () => {
const randomObject = { foo: "bar" }
const date = new Date()

expect(KurtTools.isKurtTool(randomObject)).toBe(false)
expect(KurtTools.isKurtTool(date)).toBe(false)
expect(KurtTools.isKurtTool([])).toBe(false)
})
})
23 changes: 14 additions & 9 deletions packages/kurt/src/Kurt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type {
KurtSchemaMapSingleResult,
KurtSchemaResult,
} from "./KurtSchema"
import type { KurtAdapter } from "./KurtAdapter"
import type { KurtAdapter, RawToolInput } from "./KurtAdapter"
import { KurtTools } from "./KurtTools"

/**
* Kurt wraps an LLM. You can use it to generate some output.
Expand Down Expand Up @@ -121,14 +122,18 @@ export class Kurt {
),
sampling: this.makeSamplingOptions(options.sampling),
tools: Object.fromEntries(
Object.entries(options.tools).map(([name, schema]) => [
name,
this.adapter.transformToRawTool({
name,
description: schema.description,
parameters: this.adapter.transformToRawSchema(schema),
}),
])
Object.entries(options.tools).map(([name, schemaOrTool]) => {
const rawToolInput: RawToolInput = KurtTools.isKurtTool(
schemaOrTool
)
? schemaOrTool
: {
name,
description: schemaOrTool.description,
parameters: this.adapter.transformToRawSchema(schemaOrTool),
}
return [name, this.adapter.transformToRawTool(rawToolInput)]
})
),
})
)
Expand Down
15 changes: 10 additions & 5 deletions packages/kurt/src/KurtAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
KurtSchemaMapSingleResult,
KurtSchemaResult,
} from "./KurtSchema"
import type { KurtTool } from "./KurtTools"

type V1TypeParams = {
rawMessage: object
Expand All @@ -30,6 +31,14 @@ export type KurtAdapter = KurtAdapterV1<{
rawEvent: any
}>

export type RawToolInput<A extends V1TypeParams = V1TypeParams> =
| {
name: string
description: string
parameters: A["rawSchema"]
}
| KurtTool

export interface KurtAdapterV1<A extends V1TypeParams = V1TypeParams> {
kurtAdapterVersion: "v1"

Expand All @@ -39,11 +48,7 @@ export interface KurtAdapterV1<A extends V1TypeParams = V1TypeParams> {
schema: KurtSchema<I>
): A["rawSchema"]

transformToRawTool(tool: {
name: string
description: string
parameters: A["rawSchema"]
}): A["rawTool"]
transformToRawTool(tool: RawToolInput<A>): A["rawTool"]

generateRawEvents(options: {
messages: A["rawMessage"][]
Expand Down
39 changes: 29 additions & 10 deletions packages/kurt/src/KurtError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ export abstract class KurtError extends Error {
/**
* Base class for all Kurt errors thrown for rejected requests.
*/
export abstract class KurtRequestError extends KurtError {}
export class KurtRequestError extends KurtError {
constructor(
readonly adapter: KurtAdapter,
/**
* The underlying error that was thrown when rejecting the request.
*/
innerError?: Error
) {
super(`The request was rejected: ${innerError?.message}`)
}
}

/**
* Thrown by a Kurt adapter when the request tried to use a capability or
Expand Down Expand Up @@ -50,7 +60,6 @@ export abstract class KurtResultError extends KurtError {}
export class KurtResultLimitError extends KurtResultError {
constructor(
readonly adapter: KurtAdapter,

/**
* The partial text comprising the tokens that were generated by Kurt
* before the limit was reached.
Expand All @@ -75,7 +84,6 @@ export class KurtResultLimitError extends KurtResultError {
export class KurtResultBlockedError extends KurtResultError {
constructor(
readonly adapter: KurtAdapter,

/**
* The partial text comprising the tokens that were generated by Kurt
* before the block was encountered.
Expand All @@ -85,7 +93,6 @@ export class KurtResultBlockedError extends KurtResultError {
* output from the partial text.
*/
readonly text: string,

/**
* The reason why the generated output was blocked.
*
Expand All @@ -111,7 +118,6 @@ export class KurtResultBlockedError extends KurtResultError {
export class KurtResultParseError extends KurtResultError {
constructor(
readonly adapter: KurtAdapter,

/**
* The text that Kurt failed to parse as structured data.
*
Expand All @@ -120,7 +126,6 @@ export class KurtResultParseError extends KurtResultError {
* useful information from this text.
*/
readonly text: string,

/**
* The underlying error that was thrown when parsing the generated output.
*/
Expand All @@ -142,22 +147,18 @@ export class KurtResultValidateError<
> extends KurtResultError {
constructor(
readonly adapter: KurtAdapter,

/**
* The schema that the generated output data failed to validate against.
*/
readonly schema: KurtSchema<I>,

/**
* The text associated with the generated output that failed validation.
*/
readonly text: string,

/**
* The generated output data that failed validation.
*/
readonly data: unknown,

/**
* The underlying error that was thrown when validating the generated data.
*/
Expand All @@ -166,3 +167,21 @@ export class KurtResultValidateError<
super("The generated output didn't match the required schema.")
}
}

/**
* Thrown by Kurt when the input schema provided by the caller is invalid.
*/
export class KurtInvalidInputSchemaError extends KurtError {
constructor(
/**
* The Kurt adapter that was in use when the error occurred.
*/
readonly adapter: KurtAdapter,
/**
* The underlying error that was thrown when validating the schema
*/
readonly message: string
) {
super("The input schema is invalid.")
}
}
3 changes: 2 additions & 1 deletion packages/kurt/src/KurtSchema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ZodObject, ZodRawShape, infer as zodInfer } from "zod"
import { fromJSONSchema7 } from "./KurtSchema.fromJSONSchema7"
import type { KurtTool } from "./KurtTools"

export const KurtSchema = {
fromJSONSchema7,
Expand Down Expand Up @@ -72,7 +73,7 @@ export type KurtSchemaInnerMap = { [key: string]: KurtSchemaInner }
* This is often used for a set of named tool schemas available to Kurt.
*/
export type KurtSchemaMap<I extends KurtSchemaInnerMap> = {
[key in keyof I]: KurtSchema<I[key]>
[key in keyof I]: KurtSchema<I[key]> | KurtTool
}

/**
Expand Down
Loading
Loading