@opencode/ai 0.0.0-dev-20136 → 0.0.0-dev-20138

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,15 +9,13 @@ import { OpenAI } from "@opencode/ai/providers"
9
9
 
10
10
  const openai = OpenAI.configure({ apiKey: process.env.OPENAI_API_KEY })
11
11
 
12
- const request = LLM.request({
13
- model: openai.responses("gpt-4o-mini"), // `.chat(...)` selects the Chat Completions API instead
14
- system: "You are concise.",
15
- prompt: "Say hello in one short sentence.",
16
- generation: { maxTokens: 40 },
17
- })
18
-
19
12
  const program = Effect.gen(function* () {
20
- const response = yield* LLM.generate(request)
13
+ const response = yield* LLM.generate({
14
+ model: openai.responses("gpt-4o-mini"), // `.chat(...)` selects the Chat Completions API instead
15
+ system: "You are concise.",
16
+ prompt: "Say hello in one short sentence.",
17
+ generation: { maxTokens: 40 },
18
+ })
21
19
  console.log(response.text)
22
20
  })
23
21
 
@@ -25,7 +23,8 @@ const program = Effect.gen(function* () {
25
23
  await Effect.runPromise(program.pipe(Effect.provide(AIClient.layer)))
26
24
  ```
27
25
 
28
- Run `LLM.stream(request)` instead of `generate` when you want incremental `LLMEvent`s. The event stream is provider-neutral — same shape across OpenAI Chat, OpenAI Responses,
26
+ Run `LLM.stream(...)` instead of `generate` when you want incremental `LLMEvent`s. Both accept input or a prebuilt
27
+ `LLM.request(...)`. The event stream is provider-neutral — same shape across OpenAI Chat, OpenAI Responses,
29
28
  Anthropic Messages, Gemini, Bedrock Converse, and any OpenAI-compatible deployment.
30
29
 
31
30
  The same configured facade names image, video, speech, and transcription models. `Image.generate` resolves the
@@ -72,11 +71,11 @@ helpers; `ai.file` and `ai.write` load `node:fs/promises` on first use, so no Ef
72
71
  import { AI } from "@opencode/ai/promise"
73
72
 
74
73
  const ai = AI.make()
75
- const request = ai.llm.request({ model: openai.responses("gpt-4o-mini"), prompt: "Say hello." })
76
- const text = await ai.llm.generate(request)
74
+ const input = { model: openai.responses("gpt-4o-mini"), prompt: "Say hello." }
75
+ const text = await ai.llm.generate(input)
77
76
  const generated = await ai.image.generate({ model: openai.image("gpt-image-2"), prompt: "A lighthouse" })
78
77
  await ai.write(generated.image, "./lighthouse.png") // also ai.file(path), ai.bytes(asset), ai.base64(asset), ai.materialize(asset)
79
- for await (const event of ai.llm.stream(request)) {
78
+ for await (const event of ai.llm.stream(ai.llm.request(input))) {
80
79
  // LLMEvent
81
80
  }
82
81
  await ai.dispose()
@@ -937,7 +936,7 @@ const transcript = await generation.await({ poll: { interval: 3_000 } })
937
936
  ## Public API
938
937
 
939
938
  - **`LLM.request({...})`** — build a provider-neutral `LLMRequest`. Accepts ergonomic inputs (`system: string`, `prompt: string`) that normalize into the canonical Schema classes.
940
- - **`LLM.generate` / `LLM.stream`** — re-exported from `LLMClient` for one-import use.
939
+ - **`LLM.generate` / `LLM.stream`** — run direct input or an `LLMRequest` through `LLMClient` for one-import use.
941
940
  - **`Message.user(...)` / `Message.assistant(...)` / `Message.tool(...)`** — message constructors from the canonical schema model.
942
941
  - **`LanguageModel.make(...)` / `ToolCallPart.make(...)` / `ToolResultPart.make(...)` / `ToolDefinition.make(...)`** — model and tool-related constructors from the canonical schema model.
943
942
  - **`LLMEvent.is.*`** — typed guards (`is.textDelta`, `is.toolCall`, `is.finish`, …) for filtering streams.
package/dist/llm.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Effect, JsonSchema, Schema } from "effect";
2
- import { Service } from "./route/client.js";
3
- import { GenerationOptions, HttpOptions, AIError, LLMRequest, LLMResponse, Message, LanguageModel, SystemPart, ToolChoice, type ContentPart, type LanguageModelProviderOptions, type ToolEntryInput } from "./schema/index.js";
1
+ import { Effect, JsonSchema, Schema, Stream } from "effect";
2
+ import { Service, type StreamOptions } from "./route/client.js";
3
+ import { GenerationOptions, HttpOptions, AIError, LLMEvent, LLMRequest, LLMResponse, Message, LanguageModel, SystemPart, ToolChoice, type ContentPart, type LanguageModelProviderOptions, type ToolEntryInput } from "./schema/index.js";
4
4
  import { type ToolSchema } from "./tool.js";
5
5
  /** Input accepted by `LLM.request`, normalized into the canonical `LLMRequest` class. */
6
6
  export type RequestInput<SelectedLanguageModel extends LanguageModel = LanguageModel> = Omit<ConstructorParameters<typeof LLMRequest>[0], "model" | "system" | "messages" | "tools" | "toolChoice" | "generation" | "http" | "providerOptions"> & {
@@ -14,9 +14,10 @@ export type RequestInput<SelectedLanguageModel extends LanguageModel = LanguageM
14
14
  readonly providerOptions?: NoInfer<LanguageModelProviderOptions<SelectedLanguageModel>>;
15
15
  readonly http?: HttpOptions.Input;
16
16
  };
17
- /** Run an `LLMRequest` built with `LLM.request(...)`. */
18
- export declare const generate: typeof import("./route/client.js").generate;
19
- export declare const stream: typeof import("./route/client.js").stream;
17
+ export declare function generate<const Model extends LanguageModel>(input: RequestInput<Model>, options?: StreamOptions): Effect.Effect<LLMResponse, AIError, Service>;
18
+ export declare function generate(input: LLMRequest, options?: StreamOptions): Effect.Effect<LLMResponse, AIError, Service>;
19
+ export declare function stream<const Model extends LanguageModel>(input: RequestInput<Model>, options?: StreamOptions): Stream.Stream<LLMEvent, AIError, Service>;
20
+ export declare function stream(input: LLMRequest, options?: StreamOptions): Stream.Stream<LLMEvent, AIError, Service>;
20
21
  export declare const request: <const SelectedLanguageModel extends LanguageModel>(input: RequestInput<SelectedLanguageModel>) => LLMRequest<SelectedLanguageModel>;
21
22
  type GenerateObjectBase<SelectedLanguageModel extends LanguageModel = LanguageModel> = Omit<RequestInput<SelectedLanguageModel>, "tools" | "toolChoice">;
22
23
  export declare class GenerateObjectResponse<T> {
package/dist/llm.js CHANGED
@@ -1,10 +1,15 @@
1
- import { Effect, JsonSchema, Schema } from "effect";
1
+ import { Effect, JsonSchema, Schema, Stream } from "effect";
2
+ import { tryRequest } from "./media-model.js";
2
3
  import { LLMClient, Service } from "./route/client.js";
3
4
  import { GenerationOptions, HttpOptions, InvalidProviderOutputError, AIError, LLMEvent, LLMRequest, LLMResponse, Message, LanguageModel, SystemPart, ToolChoice, ToolEntry, } from "./schema/index.js";
4
5
  import { make as makeTool, toDefinitions } from "./tool.js";
5
- /** Run an `LLMRequest` built with `LLM.request(...)`. */
6
- export const generate = LLMClient.generate;
7
- export const stream = LLMClient.stream;
6
+ export function generate(input, options) {
7
+ return requestEffect(input).pipe(Effect.flatMap((request) => LLMClient.generate(request, options)));
8
+ }
9
+ export function stream(input, options) {
10
+ return Stream.unwrap(requestEffect(input).pipe(Effect.map((request) => LLMClient.stream(request, options))));
11
+ }
12
+ const requestEffect = (input) => input instanceof LLMRequest ? Effect.succeed(input) : tryRequest(() => request(input));
8
13
  export const request = (input) => {
9
14
  const { system: requestSystem, prompt, messages, tools, toolChoice: requestToolChoice, generation: requestGeneration, providerOptions: requestProviderOptions, http: requestHttp, ...rest } = input;
10
15
  return new LLMRequest({
package/dist/promise.d.ts CHANGED
@@ -2,10 +2,10 @@ import { Effect, Layer } from "effect";
2
2
  import { AIClient } from "./ai-client.js";
3
3
  import type { AwaitOptions, Event, Snapshot } from "./generation.js";
4
4
  import { ImageModel, ImageRequest, type ImageOptions, type ImageRequestInput } from "./image.js";
5
- import { LLM } from "./index.js";
6
5
  import { Media } from "./media.js";
7
6
  import { RequestExecutor } from "./route/executor.js";
8
- import { type LLMRequest } from "./schema/index.js";
7
+ import { LanguageModel, LLMRequest } from "./schema/index.js";
8
+ import type { RequestInput } from "./llm.js";
9
9
  import { SpeechModel, SpeechRequest, type SpeechRequestInput } from "./speech.js";
10
10
  import { TranscriptionModel, TranscriptionRequest, type TranscriptionOptions, type TranscriptionRequestInput } from "./transcription.js";
11
11
  import { VideoModel, VideoRequest, type VideoOptions, type VideoRequestInput } from "./video.js";
@@ -49,9 +49,9 @@ export declare const make: (options?: Options) => {
49
49
  /** Write an asset's bytes like `Media.write`, downloading `url` sources through the executor. */
50
50
  write: (asset: Media.Asset, path: string, options?: RunOptions) => Promise<void>;
51
51
  llm: {
52
- request: <const SelectedLanguageModel extends import("./index.js").LanguageModel>(input: LLM.RequestInput<SelectedLanguageModel>) => LLMRequest<SelectedLanguageModel>;
53
- generate: (request: LLMRequest, options?: RunOptions) => Promise<import("./index.js").LLMResponse>;
54
- stream: (request: LLMRequest, options?: RunOptions) => AsyncIterable<({
52
+ request: <const SelectedLanguageModel extends LanguageModel>(input: RequestInput<SelectedLanguageModel>) => LLMRequest<SelectedLanguageModel>;
53
+ generate: <const Model extends LanguageModel>(input: RequestInput<Model> | LLMRequest, options?: RunOptions) => Promise<import("./index.js").LLMResponse>;
54
+ stream: <const Model extends LanguageModel>(input: RequestInput<Model> | LLMRequest, options?: RunOptions) => AsyncIterable<({
55
55
  readonly type: "compaction";
56
56
  readonly provider: string & import("effect/Brand").Brand<"AI.ProviderID">;
57
57
  readonly id?: string | undefined;
@@ -528,9 +528,9 @@ export declare const ai: {
528
528
  /** Write an asset's bytes like `Media.write`, downloading `url` sources through the executor. */
529
529
  write: (asset: Media.Asset, path: string, options?: RunOptions) => Promise<void>;
530
530
  llm: {
531
- request: <const SelectedLanguageModel extends import("./index.js").LanguageModel>(input: LLM.RequestInput<SelectedLanguageModel>) => LLMRequest<SelectedLanguageModel>;
532
- generate: (request: LLMRequest, options?: RunOptions) => Promise<import("./index.js").LLMResponse>;
533
- stream: (request: LLMRequest, options?: RunOptions) => AsyncIterable<({
531
+ request: <const SelectedLanguageModel extends LanguageModel>(input: RequestInput<SelectedLanguageModel>) => LLMRequest<SelectedLanguageModel>;
532
+ generate: <const Model extends LanguageModel>(input: RequestInput<Model> | LLMRequest, options?: RunOptions) => Promise<import("./index.js").LLMResponse>;
533
+ stream: <const Model extends LanguageModel>(input: RequestInput<Model> | LLMRequest, options?: RunOptions) => AsyncIterable<({
534
534
  readonly type: "compaction";
535
535
  readonly provider: string & import("effect/Brand").Brand<"AI.ProviderID">;
536
536
  readonly id?: string | undefined;
package/dist/promise.js CHANGED
@@ -3,8 +3,9 @@ import { AIClient } from "./ai-client.js";
3
3
  import { Image, ImageModel, ImageRequest } from "./image.js";
4
4
  import { LLM } from "./index.js";
5
5
  import { Media } from "./media.js";
6
+ import { tryRequest } from "./media-model.js";
6
7
  import { RequestExecutor } from "./route/executor.js";
7
- import { AIError, InvalidRequestError } from "./schema/index.js";
8
+ import { AIError, InvalidRequestError, LanguageModel, LLMRequest } from "./schema/index.js";
8
9
  import { Speech, SpeechModel, SpeechRequest } from "./speech.js";
9
10
  import { Transcription, TranscriptionModel, TranscriptionRequest, } from "./transcription.js";
10
11
  import { fileMediaType } from "./utils/media-type.js";
@@ -35,6 +36,7 @@ export const make = (options = {}) => {
35
36
  cancel: (options) => run(generation.cancel(), options),
36
37
  });
37
38
  // The typed `generate`/`stream` overloads take a concrete input or a request, not the union; normalize once here.
39
+ const llmRequest = (input) => input instanceof LLMRequest ? Effect.succeed(input) : tryRequest(() => LLM.request(input));
38
40
  const imageRequest = (input) => input instanceof ImageRequest ? input : Image.request(input);
39
41
  const videoRequest = (input) => input instanceof VideoRequest ? input : Video.request(input);
40
42
  const speechRequest = (input) => input instanceof SpeechRequest ? input : Speech.request(input);
@@ -67,8 +69,8 @@ export const make = (options = {}) => {
67
69
  },
68
70
  llm: {
69
71
  request: LLM.request,
70
- generate: (request, options) => run(LLM.generate(request), options),
71
- stream: (request, options) => iterate(LLM.stream(request), options),
72
+ generate: (input, options) => run(Effect.flatMap(llmRequest(input), LLM.generate), options),
73
+ stream: (input, options) => iterate(Stream.unwrap(Effect.map(llmRequest(input), LLM.stream)), options),
72
74
  },
73
75
  image: {
74
76
  request: Image.request,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "0.0.0-dev-20136",
3
+ "version": "0.0.0-dev-20138",
4
4
  "name": "@opencode/ai",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "devDependencies": {
35
35
  "@clack/prompts": "1.0.0-alpha.1",
36
36
  "@effect/platform-node": "4.0.0-rc.112",
37
- "@opencode/http-recorder": "0.0.0-dev-20136",
37
+ "@opencode/http-recorder": "0.0.0-dev-20138",
38
38
  "@tsconfig/bun": "1.0.9",
39
39
  "@types/bun": "1.4.0",
40
40
  "@typescript/native-preview": "7.0.0-dev.20251207.1",
@@ -44,7 +44,7 @@
44
44
  "@aws-sdk/credential-providers": "3.1057.0",
45
45
  "@smithy/eventstream-codec": "4.2.14",
46
46
  "@smithy/util-utf8": "4.2.2",
47
- "@opencode/schema": "0.0.0-dev-20136",
47
+ "@opencode/schema": "0.0.0-dev-20138",
48
48
  "aws4fetch": "1.0.20",
49
49
  "effect": "4.0.0-rc.112",
50
50
  "google-auth-library": "10.5.0"