feat(ai): publish package
This commit is contained in:
@@ -168,6 +168,7 @@
|
|||||||
"@tsconfig/bun": "catalog:",
|
"@tsconfig/bun": "catalog:",
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
"@typescript/native-preview": "catalog:",
|
"@typescript/native-preview": "catalog:",
|
||||||
|
"typescript": "catalog:",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/console/app": {
|
"packages/console/app": {
|
||||||
|
|||||||
@@ -4,47 +4,18 @@
|
|||||||
"name": "@opencode-ai/ai",
|
"name": "@opencode-ai/ai",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"setup:recording-env": "bun run script/setup-recording-env.ts",
|
"setup:recording-env": "bun run script/setup-recording-env.ts",
|
||||||
"test": "bun test --timeout 30000 --only-failures",
|
"test": "bun test --timeout 30000 --only-failures",
|
||||||
"typecheck": "tsgo --noEmit"
|
"typecheck": "tsgo --noEmit",
|
||||||
|
"build": "tsc -p tsconfig.build.json"
|
||||||
},
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
"./route": "./src/route/index.ts",
|
"./*": "./src/*.ts"
|
||||||
"./provider": "./src/provider.ts",
|
|
||||||
"./providers": "./src/providers/index.ts",
|
|
||||||
"./provider-package": "./src/provider-package.ts",
|
|
||||||
"./providers/amazon-bedrock": "./src/providers/amazon-bedrock.ts",
|
|
||||||
"./providers/anthropic": "./src/providers/anthropic.ts",
|
|
||||||
"./providers/anthropic-compatible": "./src/providers/anthropic-compatible.ts",
|
|
||||||
"./providers/azure": "./src/providers/azure.ts",
|
|
||||||
"./providers/azure/responses": "./src/providers/azure/responses.ts",
|
|
||||||
"./providers/azure/chat": "./src/providers/azure/chat.ts",
|
|
||||||
"./providers/cloudflare": "./src/providers/cloudflare.ts",
|
|
||||||
"./providers/github-copilot": "./src/providers/github-copilot.ts",
|
|
||||||
"./providers/google": "./src/providers/google.ts",
|
|
||||||
"./providers/google-vertex": "./src/providers/google-vertex.ts",
|
|
||||||
"./providers/google-vertex/anthropic": "./src/providers/google-vertex/anthropic.ts",
|
|
||||||
"./providers/openai": "./src/providers/openai.ts",
|
|
||||||
"./providers/openai/responses": "./src/providers/openai/responses.ts",
|
|
||||||
"./providers/openai/chat": "./src/providers/openai/chat.ts",
|
|
||||||
"./providers/openai-compatible": "./src/providers/openai-compatible.ts",
|
|
||||||
"./providers/openai-compatible/responses": "./src/providers/openai-compatible-responses.ts",
|
|
||||||
"./providers/openai-compatible-profile": "./src/providers/openai-compatible-profile.ts",
|
|
||||||
"./providers/openrouter": "./src/providers/openrouter.ts",
|
|
||||||
"./providers/xai": "./src/providers/xai.ts",
|
|
||||||
"./protocols": "./src/protocols/index.ts",
|
|
||||||
"./protocols/anthropic-messages": "./src/protocols/anthropic-messages.ts",
|
|
||||||
"./protocols/bedrock-converse": "./src/protocols/bedrock-converse.ts",
|
|
||||||
"./protocols/gemini": "./src/protocols/gemini.ts",
|
|
||||||
"./protocols/google-vertex-anthropic": "./src/protocols/google-vertex-anthropic.ts",
|
|
||||||
"./protocols/google-vertex-gemini": "./src/protocols/google-vertex-gemini.ts",
|
|
||||||
"./protocols/openai-chat": "./src/protocols/openai-chat.ts",
|
|
||||||
"./protocols/openai-compatible-chat": "./src/protocols/openai-compatible-chat.ts",
|
|
||||||
"./protocols/openai-compatible-responses": "./src/protocols/openai-compatible-responses.ts",
|
|
||||||
"./protocols/openai-responses": "./src/protocols/openai-responses.ts"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@clack/prompts": "1.0.0-alpha.1",
|
"@clack/prompts": "1.0.0-alpha.1",
|
||||||
@@ -52,7 +23,8 @@
|
|||||||
"@opencode-ai/http-recorder": "workspace:*",
|
"@opencode-ai/http-recorder": "workspace:*",
|
||||||
"@tsconfig/bun": "catalog:",
|
"@tsconfig/bun": "catalog:",
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
"@typescript/native-preview": "catalog:"
|
"@typescript/native-preview": "catalog:",
|
||||||
|
"typescript": "catalog:"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@smithy/eventstream-codec": "4.2.14",
|
"@smithy/eventstream-codec": "4.2.14",
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bun
|
||||||
|
import { Script } from "@opencode-ai/script"
|
||||||
|
import { $ } from "bun"
|
||||||
|
import { fileURLToPath } from "url"
|
||||||
|
|
||||||
|
const dir = fileURLToPath(new URL("..", import.meta.url))
|
||||||
|
process.chdir(dir)
|
||||||
|
|
||||||
|
async function published(name: string, version: string) {
|
||||||
|
return (await $`npm view ${name}@${version} version`.nothrow()).exitCode === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
await $`bun run build`
|
||||||
|
const originalText = await Bun.file("package.json").text()
|
||||||
|
const pkg = JSON.parse(originalText) as {
|
||||||
|
name: string
|
||||||
|
version: string
|
||||||
|
exports: Record<string, string>
|
||||||
|
}
|
||||||
|
if (await published(pkg.name, pkg.version)) {
|
||||||
|
console.log(`already published ${pkg.name}@${pkg.version}`)
|
||||||
|
} else {
|
||||||
|
for (const [key, value] of Object.entries(pkg.exports)) {
|
||||||
|
const file = value.replace("./src/", "./dist/").replace(".ts", "")
|
||||||
|
// @ts-ignore
|
||||||
|
pkg.exports[key] = {
|
||||||
|
import: file + ".js",
|
||||||
|
types: file + ".d.ts",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Bun.write("package.json", JSON.stringify(pkg, null, 2))
|
||||||
|
try {
|
||||||
|
await $`bun pm pack`
|
||||||
|
await $`npm publish *.tgz --tag ${Script.channel} --access public`
|
||||||
|
} finally {
|
||||||
|
await Bun.write("package.json", originalText)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ export type {
|
|||||||
AnyTool,
|
AnyTool,
|
||||||
ExecutableTool,
|
ExecutableTool,
|
||||||
ExecutableTools,
|
ExecutableTools,
|
||||||
Tool as ToolShape,
|
Definition as ToolShape,
|
||||||
ToolExecute,
|
ToolExecute,
|
||||||
ToolExecuteContext,
|
ToolExecuteContext,
|
||||||
ToolModelOutputInput,
|
ToolModelOutputInput,
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./protocols/index"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { EventStreamCodec } from "@smithy/eventstream-codec"
|
import { EventStreamCodec } from "@smithy/eventstream-codec"
|
||||||
import { fromUtf8, toUtf8 } from "@smithy/util-utf8"
|
import { fromUtf8, toUtf8 } from "@smithy/util-utf8"
|
||||||
import { Effect, Stream } from "effect"
|
import { Effect, Stream } from "effect"
|
||||||
import type { Framing } from "../route/framing"
|
import { Framing } from "../route/framing"
|
||||||
import { ProviderShared } from "./shared"
|
import { ProviderShared } from "./shared"
|
||||||
|
|
||||||
// Bedrock streams responses using the AWS event stream binary protocol — each
|
// Bedrock streams responses using the AWS event stream binary protocol — each
|
||||||
@@ -79,7 +79,7 @@ const consumeFrames = (route: string) => (state: FrameBufferState, chunk: Uint8A
|
|||||||
* under its `:event-type` header so the chunk schema can match the JSON
|
* under its `:event-type` header so the chunk schema can match the JSON
|
||||||
* payload directly.
|
* payload directly.
|
||||||
*/
|
*/
|
||||||
export const framing = (route: string): Framing<object> => ({
|
export const framing = (route: string): Framing.Definition<object> => ({
|
||||||
id: "aws-event-stream",
|
id: "aws-event-stream",
|
||||||
frame: (bytes) => bytes.pipe(Stream.mapAccumEffect(() => initialFrameBuffer, consumeFrames(route))),
|
frame: (bytes) => bytes.pipe(Stream.mapAccumEffect(() => initialFrameBuffer, consumeFrames(route))),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export const OpenAIChatEvent = Schema.Struct({
|
|||||||
export type OpenAIChatEvent = Schema.Schema.Type<typeof OpenAIChatEvent>
|
export type OpenAIChatEvent = Schema.Schema.Type<typeof OpenAIChatEvent>
|
||||||
type OpenAIChatRequestMessage = LLMRequest["messages"][number]
|
type OpenAIChatRequestMessage = LLMRequest["messages"][number]
|
||||||
|
|
||||||
interface ParserState {
|
export interface ParserState {
|
||||||
readonly tools: ToolStream.State<number>
|
readonly tools: ToolStream.State<number>
|
||||||
readonly toolCallEvents: ReadonlyArray<LLMEvent>
|
readonly toolCallEvents: ReadonlyArray<LLMEvent>
|
||||||
readonly usage?: Usage
|
readonly usage?: Usage
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./providers/index"
|
||||||
@@ -6,7 +6,7 @@ const SCOPE = "https://www.googleapis.com/auth/cloud-platform"
|
|||||||
|
|
||||||
export type OAuthOptions =
|
export type OAuthOptions =
|
||||||
| { readonly accessToken?: string; readonly auth?: never }
|
| { readonly accessToken?: string; readonly auth?: never }
|
||||||
| { readonly accessToken?: never; readonly auth?: Auth }
|
| { readonly accessToken?: never; readonly auth?: Auth.Definition }
|
||||||
|
|
||||||
export type ApiKeyOptions =
|
export type ApiKeyOptions =
|
||||||
| (OAuthOptions & { readonly apiKey?: never })
|
| (OAuthOptions & { readonly apiKey?: never })
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "../openai-compatible-responses"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./route/index"
|
||||||
@@ -4,7 +4,7 @@ import { Auth } from "./auth"
|
|||||||
export type ApiKeyMode = "optional" | "required"
|
export type ApiKeyMode = "optional" | "required"
|
||||||
|
|
||||||
export type AuthOverride = {
|
export type AuthOverride = {
|
||||||
readonly auth: Auth
|
readonly auth: Auth.Definition
|
||||||
readonly apiKey?: never
|
readonly apiKey?: never
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,10 @@ export type AtLeastOne<T> = {
|
|||||||
* override, otherwise resolve `apiKey` (option > config var) and apply it as
|
* override, otherwise resolve `apiKey` (option > config var) and apply it as
|
||||||
* a bearer token.
|
* a bearer token.
|
||||||
*/
|
*/
|
||||||
export const bearer = (options: ProviderAuthOption<"optional">, envVar: string | ReadonlyArray<string>): Auth => {
|
export const bearer = (
|
||||||
|
options: ProviderAuthOption<"optional">,
|
||||||
|
envVar: string | ReadonlyArray<string>,
|
||||||
|
): Auth.Definition => {
|
||||||
if ("auth" in options && options.auth) return options.auth
|
if ("auth" in options && options.auth) return options.auth
|
||||||
return (Array.isArray(envVar) ? envVar : [envVar])
|
return (Array.isArray(envVar) ? envVar : [envVar])
|
||||||
.reduce(
|
.reduce(
|
||||||
|
|||||||
@@ -25,19 +25,19 @@ export interface AuthInput {
|
|||||||
export interface Credential {
|
export interface Credential {
|
||||||
readonly load: Effect.Effect<Redacted.Redacted, CredentialError>
|
readonly load: Effect.Effect<Redacted.Redacted, CredentialError>
|
||||||
readonly orElse: (that: Credential) => Credential
|
readonly orElse: (that: Credential) => Credential
|
||||||
readonly bearer: () => Auth
|
readonly bearer: () => Definition
|
||||||
readonly header: (name: string) => Auth
|
readonly header: (name: string) => Definition
|
||||||
readonly pipe: <A>(f: (self: Credential) => A) => A
|
readonly pipe: <A>(f: (self: Credential) => A) => A
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Auth {
|
export interface Definition {
|
||||||
readonly apply: (input: AuthInput) => Effect.Effect<Headers.Headers, AuthError>
|
readonly apply: (input: AuthInput) => Effect.Effect<Headers.Headers, AuthError>
|
||||||
readonly andThen: (that: Auth) => Auth
|
readonly andThen: (that: Definition) => Definition
|
||||||
readonly orElse: (that: Auth) => Auth
|
readonly orElse: (that: Definition) => Definition
|
||||||
readonly pipe: <A>(f: (self: Auth) => A) => A
|
readonly pipe: <A>(f: (self: Definition) => A) => A
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isAuth = (input: unknown): input is Auth =>
|
export const isAuth = (input: unknown): input is Definition =>
|
||||||
typeof input === "object" && input !== null && "apply" in input && typeof input.apply === "function"
|
typeof input === "object" && input !== null && "apply" in input && typeof input.apply === "function"
|
||||||
|
|
||||||
const credential = (load: Effect.Effect<Redacted.Redacted, CredentialError>): Credential => {
|
const credential = (load: Effect.Effect<Redacted.Redacted, CredentialError>): Credential => {
|
||||||
@@ -51,8 +51,8 @@ const credential = (load: Effect.Effect<Redacted.Redacted, CredentialError>): Cr
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
const auth = (apply: Auth["apply"]): Auth => {
|
const auth = (apply: Definition["apply"]): Definition => {
|
||||||
const self: Auth = {
|
const self: Definition = {
|
||||||
apply,
|
apply,
|
||||||
andThen: (that) =>
|
andThen: (that) =>
|
||||||
auth((input) => apply(input).pipe(Effect.flatMap((headers) => that.apply({ ...input, headers })))),
|
auth((input) => apply(input).pipe(Effect.flatMap((headers) => that.apply({ ...input, headers })))),
|
||||||
@@ -109,15 +109,15 @@ const credentialInput = (source: Secret | Credential) =>
|
|||||||
? credentialFromSecret(source, "value")
|
? credentialFromSecret(source, "value")
|
||||||
: source
|
: source
|
||||||
|
|
||||||
export function bearer(source: Secret | Credential): Auth
|
export function bearer(source: Secret | Credential): Definition
|
||||||
export function bearer(source: Secret | Credential) {
|
export function bearer(source: Secret | Credential) {
|
||||||
return credentialInput(source).bearer()
|
return credentialInput(source).bearer()
|
||||||
}
|
}
|
||||||
|
|
||||||
export const apiKey = bearer
|
export const apiKey = bearer
|
||||||
|
|
||||||
export function header(name: string): (source: Secret | Credential) => Auth
|
export function header(name: string): (source: Secret | Credential) => Definition
|
||||||
export function header(name: string, source: Secret | Credential): Auth
|
export function header(name: string, source: Secret | Credential): Definition
|
||||||
export function header(name: string, source?: Secret | Credential) {
|
export function header(name: string, source?: Secret | Credential) {
|
||||||
if (source === undefined) {
|
if (source === undefined) {
|
||||||
return (next: Secret | Credential) => credentialInput(next).header(name)
|
return (next: Secret | Credential) => credentialInput(next).header(name)
|
||||||
@@ -125,8 +125,8 @@ export function header(name: string, source?: Secret | Credential) {
|
|||||||
return credentialInput(source).header(name)
|
return credentialInput(source).header(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bearerHeader(name: string): (source: Secret | Credential) => Auth
|
export function bearerHeader(name: string): (source: Secret | Credential) => Definition
|
||||||
export function bearerHeader(name: string, source: Secret | Credential): Auth
|
export function bearerHeader(name: string, source: Secret | Credential): Definition
|
||||||
export function bearerHeader(name: string, source?: Secret | Credential) {
|
export function bearerHeader(name: string, source?: Secret | Credential) {
|
||||||
const render = (input: Secret | Credential) =>
|
const render = (input: Secret | Credential) =>
|
||||||
fromCredential(credentialInput(input), (secret) => ({ [name]: `Bearer ${secret}` }))
|
fromCredential(credentialInput(input), (secret) => ({ [name]: `Bearer ${secret}` }))
|
||||||
@@ -149,7 +149,7 @@ const toLLMError = (error: AuthError): LLMError => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const toEffect =
|
export const toEffect =
|
||||||
(input: Auth) =>
|
(input: Definition) =>
|
||||||
(authInput: AuthInput): Effect.Effect<Headers.Headers, LLMError> =>
|
(authInput: AuthInput): Effect.Effect<Headers.Headers, LLMError> =>
|
||||||
input.apply(authInput).pipe(Effect.mapError(toLLMError))
|
input.apply(authInput).pipe(Effect.mapError(toLLMError))
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Cause, Context, Effect, Layer, Schema, Stream } from "effect"
|
import { Cause, Context, Effect, Layer, Schema, Stream } from "effect"
|
||||||
import * as Option from "effect/Option"
|
import * as Option from "effect/Option"
|
||||||
import { Auth, type Auth as AuthDef } from "./auth"
|
import { Auth } from "./auth"
|
||||||
import { Endpoint, type EndpointPatch } from "./endpoint"
|
import { Endpoint, type EndpointPatch } from "./endpoint"
|
||||||
import { RequestExecutor } from "./executor"
|
import { RequestExecutor } from "./executor"
|
||||||
import type { Framing } from "./framing"
|
import { Framing } from "./framing"
|
||||||
import { HttpTransport } from "./transport"
|
import { HttpTransport } from "./transport"
|
||||||
import type { Transport, TransportRuntime } from "./transport"
|
import type { Transport, TransportRuntime } from "./transport"
|
||||||
import { WebSocketExecutor } from "./transport"
|
import { WebSocketExecutor } from "./transport"
|
||||||
@@ -40,8 +40,8 @@ export interface Route<Body, Prepared = unknown> {
|
|||||||
/** ProviderMetadata namespace emitted and consumed by this route. */
|
/** ProviderMetadata namespace emitted and consumed by this route. */
|
||||||
readonly providerMetadataKey?: string
|
readonly providerMetadataKey?: string
|
||||||
readonly protocol: ProtocolID
|
readonly protocol: ProtocolID
|
||||||
readonly endpoint: Endpoint<Body>
|
readonly endpoint: Endpoint.Definition<Body>
|
||||||
readonly auth: AuthDef
|
readonly auth: Auth.Definition
|
||||||
readonly transport: Transport<Body, Prepared, unknown>
|
readonly transport: Transport<Body, Prepared, unknown>
|
||||||
readonly defaults: RouteDefaults
|
readonly defaults: RouteDefaults
|
||||||
readonly body: RouteBody<Body>
|
readonly body: RouteBody<Body>
|
||||||
@@ -86,7 +86,7 @@ export interface RouteDefaultsInput {
|
|||||||
export interface RoutePatch<Body, Prepared> extends RouteDefaultsInput {
|
export interface RoutePatch<Body, Prepared> extends RouteDefaultsInput {
|
||||||
readonly id?: string
|
readonly id?: string
|
||||||
readonly provider?: string | ProviderID
|
readonly provider?: string | ProviderID
|
||||||
readonly auth?: AuthDef
|
readonly auth?: Auth.Definition
|
||||||
readonly transport?: Transport<Body, Prepared, unknown>
|
readonly transport?: Transport<Body, Prepared, unknown>
|
||||||
readonly endpoint?: EndpointPatch<Body>
|
readonly endpoint?: EndpointPatch<Body>
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ const mergeRouteDefaults = (base: RouteDefaults | undefined, patch: RouteDefault
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const endpointBaseURL = <Body>(endpoint: Endpoint<Body>) =>
|
const endpointBaseURL = <Body>(endpoint: Endpoint.Definition<Body>) =>
|
||||||
typeof endpoint.baseURL === "string" ? endpoint.baseURL : undefined
|
typeof endpoint.baseURL === "string" ? endpoint.baseURL : undefined
|
||||||
|
|
||||||
const mergeHeaders = (...items: ReadonlyArray<Record<string, string> | undefined>) => {
|
const mergeHeaders = (...items: ReadonlyArray<Record<string, string> | undefined>) => {
|
||||||
@@ -192,11 +192,11 @@ export interface MakeInput<Body, Frame, Event, State> {
|
|||||||
/** Semantic API contract — owns body construction, body schema, and parsing. */
|
/** Semantic API contract — owns body construction, body schema, and parsing. */
|
||||||
readonly protocol: Protocol<Body, Frame, Event, State>
|
readonly protocol: Protocol<Body, Frame, Event, State>
|
||||||
/** Where the request is sent. */
|
/** Where the request is sent. */
|
||||||
readonly endpoint: Endpoint<Body>
|
readonly endpoint: Endpoint.Definition<Body>
|
||||||
/** Per-request transport auth. Provider facades override this via `route.with(...)`. */
|
/** Per-request transport auth. Provider facades override this via `route.with(...)`. */
|
||||||
readonly auth?: AuthDef
|
readonly auth?: Auth.Definition
|
||||||
/** Stream framing — bytes -> frames before `protocol.stream.event` decoding. */
|
/** Stream framing — bytes -> frames before `protocol.stream.event` decoding. */
|
||||||
readonly framing: Framing<Frame>
|
readonly framing: Framing.Definition<Frame>
|
||||||
/** Static / per-request headers added before `auth` runs. */
|
/** Static / per-request headers added before `auth` runs. */
|
||||||
readonly headers?: (input: { readonly request: LLMRequest }) => Record<string, string>
|
readonly headers?: (input: { readonly request: LLMRequest }) => Record<string, string>
|
||||||
/** Route/request defaults used when compiling requests for this route. */
|
/** Route/request defaults used when compiling requests for this route. */
|
||||||
@@ -213,9 +213,9 @@ export interface MakeTransportInput<Body, Prepared, Frame, Event, State> {
|
|||||||
/** Semantic API contract — owns body construction, body schema, and parsing. */
|
/** Semantic API contract — owns body construction, body schema, and parsing. */
|
||||||
readonly protocol: Protocol<Body, Frame, Event, State>
|
readonly protocol: Protocol<Body, Frame, Event, State>
|
||||||
/** Where the request is sent. */
|
/** Where the request is sent. */
|
||||||
readonly endpoint: Endpoint<Body>
|
readonly endpoint: Endpoint.Definition<Body>
|
||||||
/** Per-request transport auth. Provider facades override this via `route.with(...)`. */
|
/** Per-request transport auth. Provider facades override this via `route.with(...)`. */
|
||||||
readonly auth?: AuthDef
|
readonly auth?: Auth.Definition
|
||||||
/** Static / per-request headers added before `auth` runs. */
|
/** Static / per-request headers added before `auth` runs. */
|
||||||
readonly headers?: (input: { readonly request: LLMRequest }) => Record<string, string>
|
readonly headers?: (input: { readonly request: LLMRequest }) => Record<string, string>
|
||||||
/** Runnable transport route. */
|
/** Runnable transport route. */
|
||||||
|
|||||||
@@ -19,21 +19,24 @@ export type EndpointPart<Body> = string | ((input: EndpointInput<Body>) => strin
|
|||||||
* URL embeds the model id, region, or another body field (e.g. Bedrock,
|
* URL embeds the model id, region, or another body field (e.g. Bedrock,
|
||||||
* Gemini).
|
* Gemini).
|
||||||
*/
|
*/
|
||||||
export interface Endpoint<Body> {
|
export interface Definition<Body> {
|
||||||
readonly baseURL?: string
|
readonly baseURL?: string
|
||||||
readonly path: EndpointPart<Body>
|
readonly path: EndpointPart<Body>
|
||||||
readonly query?: Record<string, string>
|
readonly query?: Record<string, string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EndpointPatch<Body> = Partial<Endpoint<Body>>
|
export type EndpointPatch<Body> = Partial<Definition<Body>>
|
||||||
|
|
||||||
/** Construct an `Endpoint` from a path string or path function. */
|
/** Construct an `Endpoint` from a path string or path function. */
|
||||||
export const path = <Body>(value: EndpointPart<Body>, options: Omit<Endpoint<Body>, "path"> = {}): Endpoint<Body> => ({
|
export const path = <Body>(
|
||||||
|
value: EndpointPart<Body>,
|
||||||
|
options: Omit<Definition<Body>, "path"> = {},
|
||||||
|
): Definition<Body> => ({
|
||||||
...options,
|
...options,
|
||||||
path: value,
|
path: value,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const merge = <Body>(base: Endpoint<Body>, patch: EndpointPatch<Body>): Endpoint<Body> => ({
|
export const merge = <Body>(base: Definition<Body>, patch: EndpointPatch<Body>): Definition<Body> => ({
|
||||||
...base,
|
...base,
|
||||||
...patch,
|
...patch,
|
||||||
baseURL: patch.baseURL ?? base.baseURL,
|
baseURL: patch.baseURL ?? base.baseURL,
|
||||||
@@ -44,7 +47,7 @@ export const merge = <Body>(base: Endpoint<Body>, patch: EndpointPatch<Body>): E
|
|||||||
const renderPart = <Body>(part: EndpointPart<Body>, input: EndpointInput<Body>) =>
|
const renderPart = <Body>(part: EndpointPart<Body>, input: EndpointInput<Body>) =>
|
||||||
typeof part === "function" ? part(input) : part
|
typeof part === "function" ? part(input) : part
|
||||||
|
|
||||||
export const render = <Body>(endpoint: Endpoint<Body>, input: EndpointInput<Body>) => {
|
export const render = <Body>(endpoint: Definition<Body>, input: EndpointInput<Body>) => {
|
||||||
const url = new URL(`${ProviderShared.trimBaseUrl(endpoint.baseURL ?? "")}${renderPart(endpoint.path, input)}`)
|
const url = new URL(`${ProviderShared.trimBaseUrl(endpoint.baseURL ?? "")}${renderPart(endpoint.path, input)}`)
|
||||||
for (const [key, value] of Object.entries(endpoint.query ?? {})) url.searchParams.set(key, value)
|
for (const [key, value] of Object.entries(endpoint.query ?? {})) url.searchParams.set(key, value)
|
||||||
return url
|
return url
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ import type { LLMError } from "../schema"
|
|||||||
* The frame type is opaque to this layer; the protocol's `decode` step turns
|
* The frame type is opaque to this layer; the protocol's `decode` step turns
|
||||||
* a frame into a typed chunk.
|
* a frame into a typed chunk.
|
||||||
*/
|
*/
|
||||||
export interface Framing<Frame> {
|
export interface Definition<Frame> {
|
||||||
readonly id: string
|
readonly id: string
|
||||||
readonly frame: (bytes: Stream.Stream<Uint8Array, LLMError>) => Stream.Stream<Frame, LLMError>
|
readonly frame: (bytes: Stream.Stream<Uint8Array, LLMError>) => Stream.Stream<Frame, LLMError>
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Server-Sent Events framing. Used by every JSON-streaming HTTP provider. */
|
/** Server-Sent Events framing. Used by every JSON-streaming HTTP provider. */
|
||||||
export const sse: Framing<string> = { id: "sse", frame: ProviderShared.sseFraming }
|
export const sse: Definition<string> = { id: "sse", frame: ProviderShared.sseFraming }
|
||||||
|
|
||||||
export * as Framing from "./framing"
|
export * as Framing from "./framing"
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ export { Framing } from "./framing"
|
|||||||
export { Protocol } from "./protocol"
|
export { Protocol } from "./protocol"
|
||||||
export { HttpTransport, WebSocketExecutor, WebSocketTransport } from "./transport"
|
export { HttpTransport, WebSocketExecutor, WebSocketTransport } from "./transport"
|
||||||
export * as Transport from "./transport"
|
export * as Transport from "./transport"
|
||||||
export type { Auth as AuthShape, AuthInput, Credential, CredentialError } from "./auth"
|
export type { Definition as AuthShape, AuthInput, Credential, CredentialError } from "./auth"
|
||||||
export type { ApiKeyMode, AuthOverride, ProviderAuthOption } from "./auth-options"
|
export type { ApiKeyMode, AuthOverride, ProviderAuthOption } from "./auth-options"
|
||||||
export type { Endpoint as EndpointFn, EndpointInput } from "./endpoint"
|
export type { Definition as EndpointFn, EndpointInput } from "./endpoint"
|
||||||
export type { Framing as FramingDef } from "./framing"
|
export type { Definition as FramingDef } from "./framing"
|
||||||
export type { Protocol as ProtocolDef } from "./protocol"
|
export type { Protocol as ProtocolDef } from "./protocol"
|
||||||
export type { Transport as TransportDef, TransportRuntime } from "./transport"
|
export type { Transport as TransportDef, TransportRuntime } from "./transport"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Effect, Stream } from "effect"
|
|||||||
import { Headers, HttpClientRequest } from "effect/unstable/http"
|
import { Headers, HttpClientRequest } from "effect/unstable/http"
|
||||||
import { Auth } from "../auth"
|
import { Auth } from "../auth"
|
||||||
import { render as renderEndpoint } from "../endpoint"
|
import { render as renderEndpoint } from "../endpoint"
|
||||||
import { Framing, type Framing as FramingDef } from "../framing"
|
import { Framing } from "../framing"
|
||||||
import type { Transport, TransportPrepareInput } from "./index"
|
import type { Transport, TransportPrepareInput } from "./index"
|
||||||
import * as ProviderShared from "../../protocols/shared"
|
import * as ProviderShared from "../../protocols/shared"
|
||||||
import { mergeJsonRecords, type LLMRequest } from "../../schema"
|
import { mergeJsonRecords, type LLMRequest } from "../../schema"
|
||||||
@@ -18,7 +18,7 @@ export interface JsonRequestParts<Body = unknown> {
|
|||||||
|
|
||||||
export interface HttpPrepared<Frame> {
|
export interface HttpPrepared<Frame> {
|
||||||
readonly request: HttpClientRequest.HttpClientRequest
|
readonly request: HttpClientRequest.HttpClientRequest
|
||||||
readonly framing: FramingDef<Frame>
|
readonly framing: Framing.Definition<Frame>
|
||||||
}
|
}
|
||||||
|
|
||||||
const applyQuery = (url: string, query: Record<string, string> | undefined) => {
|
const applyQuery = (url: string, query: Record<string, string> | undefined) => {
|
||||||
@@ -107,7 +107,7 @@ export const jsonRequestParts = <Body>(input: JsonRequestInput<Body>) =>
|
|||||||
})
|
})
|
||||||
|
|
||||||
export interface HttpJsonInput<_Body, Frame> {
|
export interface HttpJsonInput<_Body, Frame> {
|
||||||
readonly framing: FramingDef<Frame>
|
readonly framing: Framing.Definition<Frame>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HttpJsonPatch<Body, Frame> = Partial<HttpJsonInput<Body, Frame>>
|
export type HttpJsonPatch<Body, Frame> = Partial<HttpJsonInput<Body, Frame>>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Effect, Stream } from "effect"
|
import type { Effect, Stream } from "effect"
|
||||||
import type { Endpoint } from "../endpoint"
|
import { Endpoint } from "../endpoint"
|
||||||
import type { Auth } from "../auth"
|
import { Auth } from "../auth"
|
||||||
import type { Interface as RequestExecutorInterface } from "../executor"
|
import type { Interface as RequestExecutorInterface } from "../executor"
|
||||||
import type { Interface as WebSocketExecutorInterface } from "./websocket"
|
import type { Interface as WebSocketExecutorInterface } from "./websocket"
|
||||||
import type { LLMError, LLMRequest } from "../../schema"
|
import type { LLMError, LLMRequest } from "../../schema"
|
||||||
@@ -23,8 +23,8 @@ export interface Transport<Body, Prepared, Frame> {
|
|||||||
export interface TransportPrepareInput<Body> {
|
export interface TransportPrepareInput<Body> {
|
||||||
readonly body: Body
|
readonly body: Body
|
||||||
readonly request: LLMRequest
|
readonly request: LLMRequest
|
||||||
readonly endpoint: Endpoint<Body>
|
readonly endpoint: Endpoint.Definition<Body>
|
||||||
readonly auth: Auth
|
readonly auth: Auth.Definition
|
||||||
readonly encodeBody: (body: Body) => string
|
readonly encodeBody: (body: Body) => string
|
||||||
readonly headers?: (input: { readonly request: LLMRequest }) => Record<string, string>
|
readonly headers?: (input: { readonly request: LLMRequest }) => Record<string, string>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export type ToolToModelOutput<Parameters extends ToolSchema<any>, Success extend
|
|||||||
* Internally each tool also carries memoized codecs and a precomputed
|
* Internally each tool also carries memoized codecs and a precomputed
|
||||||
* `ToolDefinition` so callers do not rebuild them per invocation.
|
* `ToolDefinition` so callers do not rebuild them per invocation.
|
||||||
*/
|
*/
|
||||||
export interface Tool<Parameters extends ToolSchema<any>, Success extends ToolSchema<any>> {
|
export interface Definition<Parameters extends ToolSchema<any>, Success extends ToolSchema<any>> {
|
||||||
readonly description: string
|
readonly description: string
|
||||||
readonly parameters: Parameters
|
readonly parameters: Parameters
|
||||||
readonly success: Success
|
readonly success: Success
|
||||||
@@ -68,9 +68,9 @@ export interface Tool<Parameters extends ToolSchema<any>, Success extends ToolSc
|
|||||||
readonly _definition: ToolDefinitionClass
|
readonly _definition: ToolDefinitionClass
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AnyTool = Tool<any, any>
|
export type AnyTool = Definition<any, any>
|
||||||
|
|
||||||
export type ExecutableTool<Parameters extends ToolSchema<any>, Success extends ToolSchema<any>> = Tool<
|
export type ExecutableTool<Parameters extends ToolSchema<any>, Success extends ToolSchema<any>> = Definition<
|
||||||
Parameters,
|
Parameters,
|
||||||
Success
|
Success
|
||||||
> & {
|
> & {
|
||||||
@@ -145,7 +145,7 @@ export function make<Parameters extends ToolSchema<any>, Success extends ToolSch
|
|||||||
readonly execute?: undefined
|
readonly execute?: undefined
|
||||||
readonly toModelOutput?: ToolToModelOutput<Parameters, Success>
|
readonly toModelOutput?: ToolToModelOutput<Parameters, Success>
|
||||||
readonly toStructuredOutput?: (output: Success["Encoded"]) => unknown
|
readonly toStructuredOutput?: (output: Success["Encoded"]) => unknown
|
||||||
}): Tool<Parameters, Success>
|
}): Definition<Parameters, Success>
|
||||||
export function make(config: {
|
export function make(config: {
|
||||||
readonly description: string
|
readonly description: string
|
||||||
readonly jsonSchema: JsonSchema.JsonSchema
|
readonly jsonSchema: JsonSchema.JsonSchema
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowImportingTsExtensions": false,
|
||||||
|
"noEmit": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/tsconfig",
|
"$schema": "https://json.schemastore.org/tsconfig.json",
|
||||||
"extends": "@tsconfig/bun/tsconfig.json",
|
"extends": "@tsconfig/bun/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "dist",
|
||||||
|
"declaration": true,
|
||||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||||
"noUncheckedIndexedAccess": false,
|
"noUncheckedIndexedAccess": false
|
||||||
"plugins": [
|
},
|
||||||
{
|
"include": ["src"]
|
||||||
"name": "@effect/language-service",
|
|
||||||
"transform": "@effect/language-service/transform",
|
|
||||||
"namespaceImportPackages": ["effect", "@effect/*"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ await prepareReleaseFiles()
|
|||||||
console.log("\n=== schema ===\n")
|
console.log("\n=== schema ===\n")
|
||||||
await $`bun ./packages/schema/script/publish.ts`
|
await $`bun ./packages/schema/script/publish.ts`
|
||||||
|
|
||||||
|
console.log("\n=== ai ===\n")
|
||||||
|
await $`bun ./packages/ai/script/publish.ts`
|
||||||
|
|
||||||
console.log("\n=== protocol ===\n")
|
console.log("\n=== protocol ===\n")
|
||||||
await $`bun ./packages/protocol/script/publish.ts`
|
await $`bun ./packages/protocol/script/publish.ts`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user