MCPcopy Create free account
hub / github.com/MoonshotAI/kimi-code / generate

Function generate

packages/kosong/src/generate.ts:82–243  ·  view source on GitHub ↗
(
  provider: ChatProvider,
  systemPrompt: string,
  tools: Tool[],
  history: Message[],
  callbacks?: GenerateCallbacks,
  options?: GenerateOptions,
)

Source from the content-addressed store, hash-verified

80 * no tool calls, or only thinking content without any text or tool calls.
81 */
82export async function generate(
83 provider: ChatProvider,
84 systemPrompt: string,
85 tools: Tool[],
86 history: Message[],
87 callbacks?: GenerateCallbacks,
88 options?: GenerateOptions,
89): Promise<GenerateResult> {
90 const message: Message = { role: 'assistant', content: [], toolCalls: [] };
91 let pendingPart: StreamedMessagePart | null = null;
92
93 // Map from provider streaming index (e.g. OpenAI Chat `index`, Responses
94 // `item_id`) to the position inside `message.toolCalls`. Used to route
95 // interleaved argument deltas from parallel tool calls to the correct call.
96 const toolCallIndexMap = new Map<number | string, number>();
97
98 // Pre-flight abort check: if the caller's signal is already aborted, we
99 // must not issue the provider request at all. Providers that do not
100 // themselves honor `signal` would otherwise emit a network call that the
101 // caller has explicitly cancelled.
102 if (options?.signal?.aborted) {
103 throwAbortError();
104 }
105
106 options?.onRequestStart?.();
107 const stream = await provider.generate(systemPrompt, tools, history, options);
108
109 // Post-await abort check: `provider.generate()` may have resolved before
110 // noticing a mid-flight abort. Reject immediately rather than draining
111 // the stream.
112 await throwIfAborted(options?.signal, stream);
113
114 // Decode-phase accounting. We split the window from the first streamed part
115 // to stream end into time spent awaiting the next part (server + network) vs.
116 // time spent processing each part in-process (deep copy, host callback, part
117 // merge). `lastResumeAt` marks the end of the previous part's processing, so
118 // the gap until the next part arrives is attributed to the server. The
119 // per-part processing is wrapped in try/finally so the accounting stays
120 // correct across `continue` and thrown aborts.
121 let serverDecodeMs = 0;
122 let clientConsumeMs = 0;
123 let firstPartAt: number | undefined;
124 let lastResumeAt = 0;
125
126 for await (const part of stream) {
127 const arrivedAt = Date.now();
128 if (firstPartAt === undefined) {
129 firstPartAt = arrivedAt;
130 } else {
131 serverDecodeMs += arrivedAt - lastResumeAt;
132 }
133
134 try {
135 await throwIfAborted(options?.signal, stream);
136
137 // Notify raw part callback (deep copy to avoid aliasing mutations).
138 if (callbacks?.onMessagePart !== undefined) {
139 await callbacks.onMessagePart(deepCopyPart(part));

Calls 11

isToolCallPartFunction · 0.90
mergeInPlaceFunction · 0.90
deepCopyPartFunction · 0.85
isPendingToolCallAtIndexFunction · 0.85
flushPartFunction · 0.85
formatFinishReasonHintFunction · 0.85
throwAbortErrorFunction · 0.70
throwIfAbortedFunction · 0.70
generateMethod · 0.65
nowMethod · 0.65
getMethod · 0.65

Tested by

no test coverage detected