@yourgpt/llm-sdk 1.3.0 → 1.4.0

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/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { G as GenerateTextParams, a as GenerateTextResult, S as StreamTextParams, b as StreamTextResult, T as ToolContext, c as Tool } from './types-CdORv1Yu.js';
2
2
  export { A as AssistantMessage, C as CoreMessage, t as DEFAULT_CAPABILITIES, D as DoGenerateParams, d as DoGenerateResult, E as ErrorChunk, F as FilePart, q as FinishChunk, s as FinishReason, k as GenerateStep, I as ImagePart, L as LanguageModel, M as ModelCapabilities, R as ResponseOptions, m as StreamChunk, l as StreamPart, e as SystemMessage, n as TextDeltaChunk, h as TextPart, r as TokenUsage, i as ToolCall, o as ToolCallChunk, f as ToolMessage, j as ToolResult, p as ToolResultChunk, g as UserContentPart, U as UserMessage } from './types-CdORv1Yu.js';
3
3
  import { z } from 'zod';
4
- import { ActionDefinition, ToolDefinition, AgentLoopConfig, KnowledgeBaseConfig, DoneEventMessage, StreamEvent, Message, AIProvider as AIProvider$1, ToolResponse } from '@yourgpt/copilot-sdk/core';
4
+ import { ActionDefinition, ToolDefinition, AgentLoopConfig, KnowledgeBaseConfig, DoneEventMessage, StreamEvent, ToolCallInfo, Message, AIProvider as AIProvider$1, ToolResponse } from '@yourgpt/copilot-sdk/core';
5
5
  export { ActionDefinition, AgentLoopConfig, LLMConfig, Message, StreamEvent, ToolDefinition, ToolExecution, ToolLocation, ToolResponse, UnifiedToolCall, UnifiedToolResult } from '@yourgpt/copilot-sdk/core';
6
6
  import { A as AIProvider } from './types-0uwUGKFS.js';
7
7
  export { a as AnthropicProviderConfig, e as AnthropicTool, g as AnthropicToolResult, f as AnthropicToolUse, b as AzureProviderConfig, B as BaseProviderConfig, l as GeminiFunctionCall, k as GeminiFunctionDeclaration, m as GeminiFunctionResponse, G as GoogleProviderConfig, c as OllamaProviderConfig, O as OpenAIProviderConfig, h as OpenAITool, i as OpenAIToolCall, j as OpenAIToolResult, P as ProviderCapabilities, d as ProviderFormatter, X as XAIProviderConfig } from './types-0uwUGKFS.js';
@@ -418,6 +418,223 @@ interface HandleRequestOptions {
418
418
  onFinish?: (result: HandleRequestResult) => Promise<void> | void;
419
419
  }
420
420
 
421
+ /**
422
+ * StreamResult - Industry-standard streaming result object
423
+ *
424
+ * Provides multiple ways to consume streaming responses:
425
+ * - Web API: toResponse(), toTextResponse()
426
+ * - Node.js/Express: pipeToResponse(), pipeTextToResponse()
427
+ * - Collection: collect(), text()
428
+ * - Iteration: for await...of
429
+ *
430
+ * @example
431
+ * ```typescript
432
+ * // Express - one-liner
433
+ * app.post('/chat', async (req, res) => {
434
+ * await runtime.stream(req.body).pipeToResponse(res);
435
+ * });
436
+ *
437
+ * // Next.js
438
+ * export async function POST(req: Request) {
439
+ * const body = await req.json();
440
+ * return runtime.stream(body).toResponse();
441
+ * }
442
+ *
443
+ * // Collect full response
444
+ * const { text, messages } = await runtime.stream(body).collect();
445
+ * ```
446
+ */
447
+
448
+ /**
449
+ * Options for response methods
450
+ */
451
+ interface StreamResultOptions {
452
+ /** Additional headers to include in response */
453
+ headers?: Record<string, string>;
454
+ }
455
+ /**
456
+ * Collected result after consuming the stream
457
+ */
458
+ interface CollectedResult {
459
+ /** Accumulated text content */
460
+ text: string;
461
+ /** All messages from the stream (for persistence) */
462
+ messages: DoneEventMessage[];
463
+ /** Tool calls that were made */
464
+ toolCalls: ToolCallInfo[];
465
+ /** Whether client action is required (client-side tools) */
466
+ requiresAction: boolean;
467
+ /** Raw events (for debugging) */
468
+ events: StreamEvent[];
469
+ }
470
+ /**
471
+ * Node.js ServerResponse interface (minimal subset)
472
+ * Note: Return types are `unknown` to support both Node.js (returns `this`)
473
+ * and Express (returns `void`) response objects.
474
+ */
475
+ interface NodeServerResponse$1 {
476
+ setHeader(name: string, value: string | number | readonly string[]): unknown;
477
+ write(chunk: string | Buffer): boolean;
478
+ end(): unknown;
479
+ }
480
+ /**
481
+ * Event handler types for the on() method
482
+ */
483
+ type TextHandler = (text: string) => void;
484
+ type ToolCallHandler = (toolCall: ToolCallInfo) => void;
485
+ type DoneHandler = (result: CollectedResult) => void;
486
+ type ErrorHandler = (error: Error) => void;
487
+ /**
488
+ * StreamResult provides multiple ways to consume a streaming response.
489
+ *
490
+ * This follows the industry-standard pattern used by Vercel AI SDK,
491
+ * OpenAI SDK, and Anthropic SDK.
492
+ */
493
+ declare class StreamResult {
494
+ private generator;
495
+ private consumed;
496
+ private eventHandlers;
497
+ constructor(generator: AsyncGenerator<StreamEvent>);
498
+ /**
499
+ * Iterate over stream events
500
+ *
501
+ * @example
502
+ * ```typescript
503
+ * const result = runtime.stream(body);
504
+ * for await (const event of result) {
505
+ * if (event.type === 'message:delta') {
506
+ * console.log(event.content);
507
+ * }
508
+ * }
509
+ * ```
510
+ */
511
+ [Symbol.asyncIterator](): AsyncIterator<StreamEvent>;
512
+ /**
513
+ * Returns SSE Response for Web API frameworks
514
+ *
515
+ * @example
516
+ * ```typescript
517
+ * // Next.js App Router
518
+ * export async function POST(req: Request) {
519
+ * const body = await req.json();
520
+ * return runtime.stream(body).toResponse();
521
+ * }
522
+ * ```
523
+ */
524
+ toResponse(options?: StreamResultOptions): Response;
525
+ /**
526
+ * Alias for toResponse() - returns SSE Response
527
+ */
528
+ toSSEResponse(options?: StreamResultOptions): Response;
529
+ /**
530
+ * Returns text-only Response (no SSE events, just text content)
531
+ *
532
+ * @example
533
+ * ```typescript
534
+ * // Simple text streaming
535
+ * return runtime.stream(body).toTextResponse();
536
+ * ```
537
+ */
538
+ toTextResponse(options?: StreamResultOptions): Response;
539
+ /**
540
+ * Returns the underlying ReadableStream
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * const stream = runtime.stream(body).toReadableStream();
545
+ * // Use with custom handling
546
+ * ```
547
+ */
548
+ toReadableStream(): ReadableStream<Uint8Array>;
549
+ /**
550
+ * Pipe SSE stream to Node.js ServerResponse
551
+ *
552
+ * @example
553
+ * ```typescript
554
+ * // Express - one-liner
555
+ * app.post('/chat', async (req, res) => {
556
+ * await runtime.stream(req.body).pipeToResponse(res);
557
+ * });
558
+ * ```
559
+ */
560
+ pipeToResponse(res: NodeServerResponse$1, options?: StreamResultOptions): Promise<CollectedResult>;
561
+ /**
562
+ * Pipe text-only stream to Node.js ServerResponse
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * // Express - text-only streaming
567
+ * app.post('/chat', async (req, res) => {
568
+ * await runtime.stream(req.body).pipeTextToResponse(res);
569
+ * });
570
+ * ```
571
+ */
572
+ pipeTextToResponse(res: NodeServerResponse$1, options?: StreamResultOptions): Promise<CollectedResult>;
573
+ /**
574
+ * Collect all events and return final result
575
+ *
576
+ * @example
577
+ * ```typescript
578
+ * const { text, messages, toolCalls } = await runtime.stream(body).collect();
579
+ * console.log('Response:', text);
580
+ * ```
581
+ */
582
+ collect(): Promise<CollectedResult>;
583
+ /**
584
+ * Get final text (convenience method)
585
+ *
586
+ * @example
587
+ * ```typescript
588
+ * const text = await runtime.stream(body).text();
589
+ * ```
590
+ */
591
+ text(): Promise<string>;
592
+ /**
593
+ * Register event handler for streaming events
594
+ *
595
+ * @example
596
+ * ```typescript
597
+ * const result = runtime.stream(body)
598
+ * .on('text', (text) => console.log('Text:', text))
599
+ * .on('toolCall', (call) => console.log('Tool:', call.name))
600
+ * .on('done', (result) => console.log('Final:', result.text))
601
+ * .on('error', (err) => console.error('Error:', err));
602
+ *
603
+ * await result.pipeToResponse(res);
604
+ * ```
605
+ */
606
+ on(event: "text", handler: TextHandler): this;
607
+ on(event: "toolCall", handler: ToolCallHandler): this;
608
+ on(event: "done", handler: DoneHandler): this;
609
+ on(event: "error", handler: ErrorHandler): this;
610
+ /**
611
+ * Ensure stream hasn't been consumed
612
+ */
613
+ private ensureNotConsumed;
614
+ /**
615
+ * Create empty collector object
616
+ */
617
+ private createCollector;
618
+ /**
619
+ * Collect event into result
620
+ */
621
+ private collectEvent;
622
+ /**
623
+ * Call registered event handlers
624
+ */
625
+ private callEventHandlers;
626
+ }
627
+ /**
628
+ * Create a StreamResult from an async generator
629
+ *
630
+ * @example
631
+ * ```typescript
632
+ * const result = createStreamResult(generator);
633
+ * await result.pipeToResponse(res);
634
+ * ```
635
+ */
636
+ declare function createStreamResult(generator: AsyncGenerator<StreamEvent>): StreamResult;
637
+
421
638
  /**
422
639
  * Copilot SDK Runtime
423
640
  *
@@ -538,16 +755,107 @@ declare class Runtime {
538
755
  * Convert JSON Schema to legacy parameters format
539
756
  */
540
757
  private convertInputSchemaToParameters;
758
+ /**
759
+ * Stream chat and return StreamResult with helper methods
760
+ *
761
+ * This is the recommended API for new projects. It returns a StreamResult
762
+ * object with multiple ways to consume the response:
763
+ * - `pipeToResponse(res)` for Express/Node.js
764
+ * - `toResponse()` for Next.js/Web API
765
+ * - `collect()` for non-streaming use cases
766
+ *
767
+ * @example
768
+ * ```typescript
769
+ * // Express - one-liner
770
+ * app.post('/chat', async (req, res) => {
771
+ * await runtime.stream(req.body).pipeToResponse(res);
772
+ * });
773
+ *
774
+ * // Next.js App Router
775
+ * export async function POST(req: Request) {
776
+ * const body = await req.json();
777
+ * return runtime.stream(body).toResponse();
778
+ * }
779
+ *
780
+ * // With event handlers
781
+ * const result = runtime.stream(body)
782
+ * .on('text', (text) => console.log(text))
783
+ * .on('done', (result) => console.log('Done:', result.text));
784
+ * await result.pipeToResponse(res);
785
+ * ```
786
+ */
787
+ stream(request: ChatRequest, options?: {
788
+ signal?: AbortSignal;
789
+ }): StreamResult;
790
+ /**
791
+ * Chat and collect the full response (non-streaming)
792
+ *
793
+ * Convenience method that calls stream().collect() for you.
794
+ * Use this when you need the complete response before responding.
795
+ *
796
+ * @example
797
+ * ```typescript
798
+ * const { text, messages, toolCalls } = await runtime.chat(body);
799
+ * console.log('Response:', text);
800
+ * res.json({ response: text });
801
+ * ```
802
+ */
803
+ chat(request: ChatRequest, options?: {
804
+ signal?: AbortSignal;
805
+ }): Promise<CollectedResult>;
806
+ /**
807
+ * Create Express-compatible handler middleware
808
+ *
809
+ * Returns a function that can be used directly as Express middleware.
810
+ *
811
+ * @example
812
+ * ```typescript
813
+ * // Simple usage
814
+ * app.post('/chat', runtime.expressHandler());
815
+ *
816
+ * // With options
817
+ * app.post('/chat', runtime.expressHandler({ format: 'text' }));
818
+ * ```
819
+ */
820
+ expressHandler(options?: {
821
+ /** Response format: 'sse' (default) or 'text' */
822
+ format?: "sse" | "text";
823
+ /** Additional headers to include */
824
+ headers?: Record<string, string>;
825
+ }): (req: {
826
+ body: ChatRequest;
827
+ }, res: {
828
+ setHeader(name: string, value: string): void;
829
+ write(chunk: string): boolean;
830
+ end(): void;
831
+ status(code: number): {
832
+ json(data: unknown): void;
833
+ };
834
+ }) => Promise<void>;
541
835
  }
542
836
  /**
543
837
  * Create runtime instance
544
838
  */
545
839
  declare function createRuntime(config: RuntimeConfig): Runtime;
546
840
 
841
+ /**
842
+ * Node.js ServerResponse interface (minimal subset for type safety)
843
+ * Note: Return types are `unknown` to support both Node.js (returns `this`)
844
+ * and Express (returns `void`) response objects.
845
+ */
846
+ interface NodeServerResponse {
847
+ setHeader(name: string, value: string | number | readonly string[]): unknown;
848
+ write(chunk: string | Buffer): boolean;
849
+ end(): unknown;
850
+ }
547
851
  /**
548
852
  * Create SSE response headers
549
853
  */
550
854
  declare function createSSEHeaders(): Record<string, string>;
855
+ /**
856
+ * Create text stream response headers
857
+ */
858
+ declare function createTextStreamHeaders(): Record<string, string>;
551
859
  /**
552
860
  * Format event as SSE data
553
861
  */
@@ -559,7 +867,55 @@ declare function createEventStream(generator: AsyncGenerator<StreamEvent>): Read
559
867
  /**
560
868
  * Create SSE Response object
561
869
  */
562
- declare function createSSEResponse(generator: AsyncGenerator<StreamEvent>): Response;
870
+ declare function createSSEResponse(generator: AsyncGenerator<StreamEvent>, options?: {
871
+ headers?: Record<string, string>;
872
+ }): Response;
873
+ /**
874
+ * Create text-only stream Response (no SSE events, just text content)
875
+ *
876
+ * @example
877
+ * ```typescript
878
+ * const generator = runtime.processChatWithLoop(body);
879
+ * return createTextStreamResponse(generator);
880
+ * ```
881
+ */
882
+ declare function createTextStreamResponse(generator: AsyncGenerator<StreamEvent>, options?: {
883
+ headers?: Record<string, string>;
884
+ }): Response;
885
+ /**
886
+ * Pipe SSE stream to Node.js ServerResponse
887
+ *
888
+ * Standalone helper for piping streaming events directly to Express/Node.js responses.
889
+ *
890
+ * @example
891
+ * ```typescript
892
+ * // Express
893
+ * app.post('/chat', async (req, res) => {
894
+ * const generator = runtime.processChatWithLoop(req.body);
895
+ * await pipeSSEToResponse(generator, res);
896
+ * });
897
+ * ```
898
+ */
899
+ declare function pipeSSEToResponse(generator: AsyncGenerator<StreamEvent>, res: NodeServerResponse, options?: {
900
+ headers?: Record<string, string>;
901
+ }): Promise<void>;
902
+ /**
903
+ * Pipe text-only stream to Node.js ServerResponse
904
+ *
905
+ * Standalone helper for piping only text content to Express/Node.js responses.
906
+ *
907
+ * @example
908
+ * ```typescript
909
+ * // Express - text only
910
+ * app.post('/chat', async (req, res) => {
911
+ * const generator = runtime.processChatWithLoop(req.body);
912
+ * await pipeTextToResponse(generator, res);
913
+ * });
914
+ * ```
915
+ */
916
+ declare function pipeTextToResponse(generator: AsyncGenerator<StreamEvent>, res: NodeServerResponse, options?: {
917
+ headers?: Record<string, string>;
918
+ }): Promise<void>;
563
919
 
564
920
  /**
565
921
  * Create Hono app with chat endpoint
@@ -582,32 +938,87 @@ declare function createHonoApp(runtime: Runtime): Hono;
582
938
  */
583
939
  declare function createNextHandler(config: RuntimeConfig): (request: Request) => Promise<Response>;
584
940
  /**
585
- * Express middleware
941
+ * Express middleware (Simplified with StreamResult)
942
+ *
943
+ * Creates an Express-compatible middleware that uses the new StreamResult API.
944
+ * Much simpler internally - no more manual request/response conversion.
586
945
  *
587
946
  * @example
588
947
  * ```ts
589
948
  * import express from 'express';
590
949
  * import { createExpressMiddleware } from '@yourgpt/llm-sdk';
950
+ * import { createOpenAI } from '@yourgpt/llm-sdk/openai';
591
951
  *
592
952
  * const app = express();
953
+ * app.use(express.json());
593
954
  *
594
- * app.use('/api/chat', createExpressMiddleware({
595
- * llm: { provider: 'openai', apiKey: process.env.OPENAI_API_KEY! },
955
+ * // Simple usage
956
+ * app.post('/api/chat', createExpressMiddleware({
957
+ * provider: createOpenAI({ apiKey: process.env.OPENAI_API_KEY }),
958
+ * model: 'gpt-4o',
596
959
  * }));
960
+ *
961
+ * // With options
962
+ * app.post('/api/chat', createExpressMiddleware({
963
+ * provider: createOpenAI({ apiKey: process.env.OPENAI_API_KEY }),
964
+ * model: 'gpt-4o',
965
+ * }, { format: 'text' }));
597
966
  * ```
598
967
  */
599
- declare function createExpressMiddleware(config: RuntimeConfig): (req: {
600
- method: string;
601
- url: string;
602
- headers: Record<string, string>;
968
+ declare function createExpressMiddleware(config: RuntimeConfig, options?: {
969
+ /** Response format: 'sse' (default) or 'text' */
970
+ format?: "sse" | "text";
971
+ /** Additional headers to include */
972
+ headers?: Record<string, string>;
973
+ }): (req: {
603
974
  body: unknown;
604
975
  }, res: {
605
976
  status: (code: number) => {
606
977
  json: (data: unknown) => void;
607
978
  };
608
- setHeader: (name: string, value: string) => void;
609
- write: (data: string) => void;
610
- end: () => void;
979
+ setHeader: (name: string, value: string | number | readonly string[]) => unknown;
980
+ write: (data: string | Buffer) => boolean;
981
+ end: () => unknown;
982
+ }) => Promise<void>;
983
+ /**
984
+ * Create Express handler from existing Runtime instance
985
+ *
986
+ * Use this when you already have a Runtime instance and want to create
987
+ * an Express handler from it.
988
+ *
989
+ * @example
990
+ * ```ts
991
+ * import express from 'express';
992
+ * import { createRuntime, createExpressHandler } from '@yourgpt/llm-sdk';
993
+ * import { createOpenAI } from '@yourgpt/llm-sdk/openai';
994
+ *
995
+ * const runtime = createRuntime({
996
+ * provider: createOpenAI({ apiKey: process.env.OPENAI_API_KEY }),
997
+ * model: 'gpt-4o',
998
+ * });
999
+ *
1000
+ * const app = express();
1001
+ * app.use(express.json());
1002
+ *
1003
+ * // Use with existing runtime
1004
+ * app.post('/api/chat', createExpressHandler(runtime));
1005
+ *
1006
+ * // Or use runtime.expressHandler() directly
1007
+ * app.post('/api/chat', runtime.expressHandler());
1008
+ * ```
1009
+ */
1010
+ declare function createExpressHandler(runtime: Runtime, options?: {
1011
+ format?: "sse" | "text";
1012
+ headers?: Record<string, string>;
1013
+ }): (req: {
1014
+ body: ChatRequest;
1015
+ }, res: {
1016
+ setHeader(name: string, value: string): void;
1017
+ write(chunk: string): boolean;
1018
+ end(): void;
1019
+ status(code: number): {
1020
+ json(data: unknown): void;
1021
+ };
611
1022
  }) => Promise<void>;
612
1023
  /**
613
1024
  * Node.js HTTP handler
@@ -681,4 +1092,4 @@ interface AgentLoopOptions {
681
1092
  */
682
1093
  declare function runAgentLoop(options: AgentLoopOptions): AsyncGenerator<StreamEvent>;
683
1094
 
684
- export { AIProvider, type ActionRequest, type AgentLoopOptions, type ChatRequest, DEFAULT_MAX_ITERATIONS, GenerateTextParams, GenerateTextResult, LLMAdapter, type RequestContext, Runtime, type RuntimeConfig, StreamTextParams, StreamTextResult, Tool, ToolContext, createEventStream, createExpressMiddleware, createHonoApp, createNextHandler, createNodeHandler, createRuntime, createSSEHeaders, createSSEResponse, formatSSEData, formatToolsForAnthropic, formatToolsForGoogle, formatToolsForOpenAI, generateText, runAgentLoop, streamText, tool };
1095
+ export { AIProvider, type ActionRequest, type AgentLoopOptions, type ChatRequest, type CollectedResult, DEFAULT_MAX_ITERATIONS, GenerateTextParams, GenerateTextResult, LLMAdapter, type RequestContext, Runtime, type RuntimeConfig, StreamResult, type StreamResultOptions, StreamTextParams, StreamTextResult, Tool, ToolContext, createEventStream, createExpressHandler, createExpressMiddleware, createHonoApp, createNextHandler, createNodeHandler, createRuntime, createSSEHeaders, createSSEResponse, createStreamResult, createTextStreamHeaders, createTextStreamResponse, formatSSEData, formatToolsForAnthropic, formatToolsForGoogle, formatToolsForOpenAI, generateText, pipeSSEToResponse, pipeTextToResponse, runAgentLoop, streamText, tool };