@augmentcode/auggie-sdk 0.1.13 → 0.1.15

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
@@ -4,6 +4,15 @@ A TypeScript SDK for building AI-powered developer tools with Auggie.
4
4
 
5
5
  ## Features
6
6
 
7
+ ### 🎯 AI SDK Provider (Vercel AI SDK)
8
+ **Requires: API credentials only (no local Auggie needed)**
9
+
10
+ - Use Augment as a language model provider with Vercel's AI SDK
11
+ - Compatible with `generateText`, `streamText`, and other AI SDK functions
12
+ - Full support for tool calling (function calling) with automatic execution
13
+ - Multi-turn conversations with context retention
14
+ - Streaming responses for real-time output
15
+
7
16
  ### 🤖 Agent Interaction (ACP)
8
17
  **Requires: Local Auggie installation**
9
18
 
@@ -55,6 +64,91 @@ pnpm add /path/to/auggie-sdk
55
64
 
56
65
  ## Usage
57
66
 
67
+ ### AI SDK Provider (Vercel AI SDK)
68
+
69
+ **✅ No Local Auggie Required - API Only**
70
+
71
+ Use Augment as a language model provider with Vercel's AI SDK:
72
+
73
+ ```typescript
74
+ import { AugmentLanguageModel, resolveAugmentCredentials } from "@augmentcode/auggie-sdk";
75
+ import { generateText } from "ai";
76
+
77
+ // Resolve credentials from environment or ~/.augment/session.json
78
+ const credentials = await resolveAugmentCredentials();
79
+
80
+ // Create the Augment language model
81
+ const model = new AugmentLanguageModel("claude-sonnet-4-5", credentials);
82
+
83
+ // Use with AI SDK functions
84
+ const { text } = await generateText({
85
+ model,
86
+ prompt: "Explain TypeScript in one sentence.",
87
+ });
88
+
89
+ console.log(text);
90
+ ```
91
+
92
+ #### Streaming Responses
93
+
94
+ ```typescript
95
+ import { streamText } from "ai";
96
+
97
+ const { textStream } = await streamText({
98
+ model,
99
+ prompt: "Write a haiku about coding.",
100
+ });
101
+
102
+ for await (const chunk of textStream) {
103
+ process.stdout.write(chunk);
104
+ }
105
+ ```
106
+
107
+ #### Tool Calling (Function Calling)
108
+
109
+ ```typescript
110
+ import { generateText, tool } from "ai";
111
+ import { z } from "zod";
112
+
113
+ const weatherTool = tool({
114
+ description: "Get the current weather in a location",
115
+ parameters: z.object({
116
+ location: z.string(),
117
+ }),
118
+ execute: async ({ location }) => {
119
+ // Your implementation
120
+ return { temperature: 72, conditions: "sunny" };
121
+ },
122
+ });
123
+
124
+ const { text } = await generateText({
125
+ model,
126
+ tools: {
127
+ getWeather: weatherTool,
128
+ },
129
+ maxSteps: 5, // Enable multi-step agentic loop
130
+ prompt: "What's the weather in San Francisco?",
131
+ });
132
+ ```
133
+
134
+ #### Multi-turn Conversations
135
+
136
+ ```typescript
137
+ import { type CoreMessage } from "ai";
138
+
139
+ const messages: CoreMessage[] = [
140
+ { role: "user", content: "What is TypeScript?" },
141
+ ];
142
+
143
+ const response1 = await generateText({ model, messages });
144
+ messages.push({ role: "assistant", content: response1.text });
145
+
146
+ messages.push({ role: "user", content: "What are its benefits?" });
147
+ const response2 = await generateText({ model, messages });
148
+ ```
149
+
150
+ **See [examples/ai-sdk-README.md](examples/ai-sdk-README.md) for more detailed examples.**
151
+
58
152
  ### Agent Interaction (ACP)
59
153
 
60
154
  **⚠️ Requires Local Auggie Installation**
@@ -0,0 +1,113 @@
1
+ import { LanguageModelV2, LanguageModelV2CallOptions, LanguageModelV2StreamPart } from '@ai-sdk/provider';
2
+ import { ResolvedCredentials } from '../context/internal/credentials.js';
3
+
4
+ /**
5
+ * Augment Language Model - AI SDK LanguageModelV2 implementation using Augment's API.
6
+ *
7
+ * This module provides an implementation of the AI SDK's LanguageModelV2 interface
8
+ * that uses Augment's chat API. It enables using Augment as a model provider with
9
+ * generateText/streamText from the Vercel AI SDK.
10
+ *
11
+ * Supports:
12
+ * - Text generation
13
+ * - Tool calling (function tools)
14
+ * - Multi-turn conversations with tool results
15
+ * - Streaming responses
16
+ *
17
+ * @module auggie/ai-sdk-provider
18
+ */
19
+
20
+ /** Configuration for the Augment language model */
21
+ interface AugmentLanguageModelConfig {
22
+ /** API key for authentication */
23
+ apiKey: string;
24
+ /** Augment API URL */
25
+ apiUrl: string;
26
+ /** Enable debug logging */
27
+ debug?: boolean;
28
+ /**
29
+ * Custom User-Agent string to use instead of the default SDK User-Agent.
30
+ * If not provided, defaults to "augment.sdk.ai/{version} (typescript)".
31
+ * Example: "context-connectors/0.1.3 via:cli-agent"
32
+ */
33
+ clientUserAgent?: string;
34
+ }
35
+ /** Resolved credentials for Augment API (re-export for convenience) */
36
+ type AugmentCredentials = ResolvedCredentials;
37
+ /**
38
+ * Resolve Augment API credentials from environment variables or session file.
39
+ *
40
+ * Priority order:
41
+ * 1. AUGMENT_API_TOKEN and AUGMENT_API_URL environment variables
42
+ * 2. ~/.augment/session.json (created by `auggie login`)
43
+ *
44
+ * @returns Resolved credentials
45
+ * @throws Error if credentials cannot be resolved
46
+ */
47
+ declare function resolveAugmentCredentials(): Promise<AugmentCredentials>;
48
+ /**
49
+ * Augment Language Model implementation for the AI SDK.
50
+ *
51
+ * Implements LanguageModelV2 to enable use with generateText/streamText.
52
+ * Supports text generation, tool calling, and multi-turn conversations.
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * import { AugmentLanguageModel, resolveAugmentCredentials } from "@augmentcode/auggie-sdk";
57
+ * import { generateText } from "ai";
58
+ *
59
+ * const credentials = await resolveAugmentCredentials();
60
+ * const model = new AugmentLanguageModel("sonnet4.5", credentials);
61
+ *
62
+ * const { text } = await generateText({
63
+ * model,
64
+ * prompt: "Hello, world!",
65
+ * });
66
+ * ```
67
+ *
68
+ * @example Tool calling with agentic loop
69
+ * ```typescript
70
+ * import { generateText, tool } from "ai";
71
+ * import { z } from "zod";
72
+ *
73
+ * const { text, toolCalls } = await generateText({
74
+ * model,
75
+ * tools: {
76
+ * search: tool({
77
+ * description: "Search for information",
78
+ * parameters: z.object({ query: z.string() }),
79
+ * execute: async ({ query }) => searchDatabase(query),
80
+ * }),
81
+ * },
82
+ * maxSteps: 10,
83
+ * prompt: "Find information about...",
84
+ * });
85
+ * ```
86
+ */
87
+ declare class AugmentLanguageModel implements LanguageModelV2 {
88
+ readonly specificationVersion = "v2";
89
+ readonly provider = "augment";
90
+ readonly modelId: string;
91
+ private readonly apiKey;
92
+ private readonly apiUrl;
93
+ private readonly sessionId;
94
+ private readonly debug;
95
+ private readonly userAgent;
96
+ constructor(modelId: string, config: AugmentLanguageModelConfig);
97
+ private log;
98
+ private getHeaders;
99
+ private buildPayload;
100
+ doGenerate(options: LanguageModelV2CallOptions): ReturnType<LanguageModelV2["doGenerate"]>;
101
+ /**
102
+ * Parse streaming response and collect content, usage, and finish reason
103
+ */
104
+ private parseStreamResponse;
105
+ doStream(options: LanguageModelV2CallOptions): PromiseLike<{
106
+ stream: ReadableStream<LanguageModelV2StreamPart>;
107
+ }>;
108
+ readonly supportsImageUrls = false;
109
+ readonly supportsStructuredOutputs = false;
110
+ readonly supportedUrls: {};
111
+ }
112
+
113
+ export { type AugmentCredentials, AugmentLanguageModel, type AugmentLanguageModelConfig, resolveAugmentCredentials };
@@ -0,0 +1,518 @@
1
+ import { v4 as uuidv4 } from "uuid";
2
+ import { getSDKVersion } from "../version.js";
3
+ import { resolveCredentials } from "../context/internal/credentials.js";
4
+ async function resolveAugmentCredentials() {
5
+ return resolveCredentials();
6
+ }
7
+ var ChatRequestNodeType = /* @__PURE__ */ ((ChatRequestNodeType2) => {
8
+ ChatRequestNodeType2[ChatRequestNodeType2["TEXT"] = 0] = "TEXT";
9
+ ChatRequestNodeType2[ChatRequestNodeType2["TOOL_RESULT"] = 1] = "TOOL_RESULT";
10
+ ChatRequestNodeType2[ChatRequestNodeType2["IMAGE"] = 2] = "IMAGE";
11
+ ChatRequestNodeType2[ChatRequestNodeType2["IMAGE_ID"] = 3] = "IMAGE_ID";
12
+ ChatRequestNodeType2[ChatRequestNodeType2["IDE_STATE"] = 4] = "IDE_STATE";
13
+ ChatRequestNodeType2[ChatRequestNodeType2["EDIT_EVENTS"] = 5] = "EDIT_EVENTS";
14
+ return ChatRequestNodeType2;
15
+ })(ChatRequestNodeType || {});
16
+ var ChatResultNodeType = /* @__PURE__ */ ((ChatResultNodeType2) => {
17
+ ChatResultNodeType2[ChatResultNodeType2["RAW_RESPONSE"] = 0] = "RAW_RESPONSE";
18
+ ChatResultNodeType2[ChatResultNodeType2["SUGGESTED_QUESTIONS"] = 1] = "SUGGESTED_QUESTIONS";
19
+ ChatResultNodeType2[ChatResultNodeType2["MAIN_TEXT_FINISHED"] = 2] = "MAIN_TEXT_FINISHED";
20
+ ChatResultNodeType2[ChatResultNodeType2["WORKSPACE_FILE_CHUNKS"] = 3] = "WORKSPACE_FILE_CHUNKS";
21
+ ChatResultNodeType2[ChatResultNodeType2["RELEVANT_SOURCES"] = 4] = "RELEVANT_SOURCES";
22
+ ChatResultNodeType2[ChatResultNodeType2["TOOL_USE"] = 5] = "TOOL_USE";
23
+ ChatResultNodeType2[ChatResultNodeType2["TOOL_USE_START"] = 7] = "TOOL_USE_START";
24
+ ChatResultNodeType2[ChatResultNodeType2["THINKING"] = 8] = "THINKING";
25
+ ChatResultNodeType2[ChatResultNodeType2["BILLING_METADATA"] = 9] = "BILLING_METADATA";
26
+ ChatResultNodeType2[ChatResultNodeType2["TOKEN_USAGE"] = 10] = "TOKEN_USAGE";
27
+ return ChatResultNodeType2;
28
+ })(ChatResultNodeType || {});
29
+ var ChatStopReason = /* @__PURE__ */ ((ChatStopReason2) => {
30
+ ChatStopReason2[ChatStopReason2["REASON_UNSPECIFIED"] = 0] = "REASON_UNSPECIFIED";
31
+ ChatStopReason2[ChatStopReason2["END_TURN"] = 1] = "END_TURN";
32
+ ChatStopReason2[ChatStopReason2["MAX_TOKENS"] = 2] = "MAX_TOKENS";
33
+ ChatStopReason2[ChatStopReason2["TOOL_USE_REQUESTED"] = 3] = "TOOL_USE_REQUESTED";
34
+ ChatStopReason2[ChatStopReason2["SAFETY"] = 4] = "SAFETY";
35
+ ChatStopReason2[ChatStopReason2["RECITATION"] = 5] = "RECITATION";
36
+ ChatStopReason2[ChatStopReason2["MALFORMED_FUNCTION_CALL"] = 6] = "MALFORMED_FUNCTION_CALL";
37
+ return ChatStopReason2;
38
+ })(ChatStopReason || {});
39
+ function extractText(content) {
40
+ if (typeof content === "string") {
41
+ return content;
42
+ }
43
+ if (Array.isArray(content)) {
44
+ return content.filter((p) => typeof p === "object" && p !== null && p.type === "text").map((p) => p.text).join("");
45
+ }
46
+ return "";
47
+ }
48
+ function toolsToDefinitions(tools) {
49
+ if (!tools) return [];
50
+ return tools.filter((t) => t.type === "function").map((t) => ({
51
+ name: t.name,
52
+ description: t.description ?? "",
53
+ input_schema_json: JSON.stringify(t.inputSchema)
54
+ }));
55
+ }
56
+ function userMessageToNodes(msg, startId) {
57
+ const nodes = [];
58
+ let text = "";
59
+ let id = startId;
60
+ if (msg.role !== "user") return { nodes, text };
61
+ for (const part of msg.content) {
62
+ if (part.type === "text") {
63
+ nodes.push({
64
+ id: id++,
65
+ type: 0 /* TEXT */,
66
+ text_node: { content: part.text }
67
+ });
68
+ text += part.text;
69
+ }
70
+ }
71
+ return { nodes, text };
72
+ }
73
+ function toolMessageToNodes(msg, startId) {
74
+ const nodes = [];
75
+ let id = startId;
76
+ if (msg.role !== "tool") return nodes;
77
+ for (const part of msg.content) {
78
+ if (part.type === "tool-result") {
79
+ let content = "";
80
+ let isError = false;
81
+ const output = part.output;
82
+ if (output.type === "text") {
83
+ content = output.value;
84
+ } else if (output.type === "json") {
85
+ content = JSON.stringify(output.value);
86
+ } else if (output.type === "error-text") {
87
+ content = output.value;
88
+ isError = true;
89
+ } else if (output.type === "error-json") {
90
+ content = JSON.stringify(output.value);
91
+ isError = true;
92
+ } else if (output.type === "content") {
93
+ content = output.value.filter((v) => v.type === "text").map((v) => v.text).join("\n");
94
+ }
95
+ nodes.push({
96
+ id: id++,
97
+ type: 1 /* TOOL_RESULT */,
98
+ tool_result_node: {
99
+ tool_use_id: part.toolCallId,
100
+ content,
101
+ is_error: isError
102
+ }
103
+ });
104
+ }
105
+ }
106
+ return nodes;
107
+ }
108
+ function assistantMessageToResponseNodes(msg) {
109
+ const nodes = [];
110
+ let text = "";
111
+ let id = 0;
112
+ if (msg.role !== "assistant") return { nodes, text };
113
+ for (const part of msg.content) {
114
+ if (part.type === "text") {
115
+ text += part.text;
116
+ nodes.push({
117
+ id: id++,
118
+ type: 0 /* RAW_RESPONSE */,
119
+ content: part.text
120
+ });
121
+ } else if (part.type === "tool-call") {
122
+ nodes.push({
123
+ id: id++,
124
+ type: 5 /* TOOL_USE */,
125
+ tool_use: {
126
+ tool_use_id: part.toolCallId,
127
+ tool_name: part.toolName,
128
+ input_json: typeof part.input === "string" ? part.input : JSON.stringify(part.input)
129
+ }
130
+ });
131
+ } else if (part.type === "reasoning") {
132
+ nodes.push({
133
+ id: id++,
134
+ type: 8 /* THINKING */,
135
+ thinking: { content: part.text }
136
+ });
137
+ }
138
+ }
139
+ return { nodes, text };
140
+ }
141
+ function buildChatRequest(prompt, tools) {
142
+ const chatHistory = [];
143
+ let pendingRequestNodes = [];
144
+ let pendingRequestText = "";
145
+ let nodeId = 0;
146
+ for (const msg of prompt) {
147
+ if (msg.role === "system") {
148
+ const systemText = extractText(msg.content);
149
+ if (systemText) {
150
+ pendingRequestNodes.push({
151
+ id: nodeId++,
152
+ type: 0 /* TEXT */,
153
+ text_node: { content: `System: ${systemText}` }
154
+ });
155
+ pendingRequestText += `System: ${systemText}
156
+
157
+ `;
158
+ }
159
+ } else if (msg.role === "user") {
160
+ const { nodes, text } = userMessageToNodes(msg, nodeId);
161
+ pendingRequestNodes.push(...nodes);
162
+ nodeId += nodes.length;
163
+ if (pendingRequestText && text) {
164
+ pendingRequestText += "\n" + text;
165
+ } else {
166
+ pendingRequestText += text;
167
+ }
168
+ } else if (msg.role === "tool") {
169
+ const nodes = toolMessageToNodes(msg, nodeId);
170
+ pendingRequestNodes.push(...nodes);
171
+ nodeId += nodes.length;
172
+ } else if (msg.role === "assistant") {
173
+ const { nodes: responseNodes, text: responseText } = assistantMessageToResponseNodes(msg);
174
+ chatHistory.push({
175
+ request_message: pendingRequestText,
176
+ request_nodes: pendingRequestNodes,
177
+ response_text: responseText,
178
+ response_nodes: responseNodes
179
+ });
180
+ pendingRequestNodes = [];
181
+ pendingRequestText = "";
182
+ nodeId = 0;
183
+ }
184
+ }
185
+ pendingRequestNodes.forEach((node, i) => {
186
+ node.id = i;
187
+ });
188
+ return {
189
+ message: pendingRequestText,
190
+ nodes: pendingRequestNodes,
191
+ chatHistory,
192
+ toolDefinitions: toolsToDefinitions(tools)
193
+ };
194
+ }
195
+ function stopReasonToFinishReason(stopReason) {
196
+ switch (stopReason) {
197
+ case 1 /* END_TURN */:
198
+ return "stop";
199
+ case 2 /* MAX_TOKENS */:
200
+ return "length";
201
+ case 3 /* TOOL_USE_REQUESTED */:
202
+ return "tool-calls";
203
+ case 4 /* SAFETY */:
204
+ case 5 /* RECITATION */:
205
+ return "content-filter";
206
+ case 6 /* MALFORMED_FUNCTION_CALL */:
207
+ return "error";
208
+ default:
209
+ return "unknown";
210
+ }
211
+ }
212
+ function responseNodeToContent(node) {
213
+ if (node.type === 5 /* TOOL_USE */ && node.tool_use) {
214
+ return {
215
+ type: "tool-call",
216
+ toolCallId: node.tool_use.tool_use_id,
217
+ toolName: node.tool_use.tool_name,
218
+ input: node.tool_use.input_json || "{}"
219
+ };
220
+ }
221
+ if (node.type === 8 /* THINKING */ && node.thinking) {
222
+ const text = node.thinking.content || node.thinking.summary || "";
223
+ if (text) {
224
+ return { type: "reasoning", text };
225
+ }
226
+ }
227
+ return null;
228
+ }
229
+ class AugmentLanguageModel {
230
+ specificationVersion = "v2";
231
+ provider = "augment";
232
+ modelId;
233
+ apiKey;
234
+ apiUrl;
235
+ sessionId;
236
+ debug;
237
+ userAgent;
238
+ constructor(modelId, config) {
239
+ this.modelId = modelId;
240
+ this.apiKey = config.apiKey;
241
+ this.apiUrl = config.apiUrl.endsWith("/") ? config.apiUrl.slice(0, -1) : config.apiUrl;
242
+ this.sessionId = uuidv4();
243
+ this.debug = config.debug ?? false;
244
+ this.userAgent = config.clientUserAgent?.trim() || `augment.sdk.ai/${getSDKVersion()} (typescript)`;
245
+ }
246
+ log(message) {
247
+ if (this.debug) {
248
+ console.log(`[Augment] ${message}`);
249
+ }
250
+ }
251
+ getHeaders(requestId) {
252
+ return {
253
+ "Content-Type": "application/json",
254
+ Authorization: `Bearer ${this.apiKey}`,
255
+ "X-Request-Session-Id": this.sessionId,
256
+ "X-Request-Id": requestId,
257
+ "conversation-id": this.sessionId,
258
+ "X-Mode": "sdk",
259
+ "User-Agent": this.userAgent
260
+ };
261
+ }
262
+ buildPayload(options) {
263
+ const { message, nodes, chatHistory, toolDefinitions } = buildChatRequest(
264
+ options.prompt,
265
+ options.tools
266
+ );
267
+ return {
268
+ mode: "CLI_AGENT",
269
+ model: this.modelId,
270
+ message,
271
+ nodes,
272
+ chat_history: chatHistory,
273
+ conversation_id: this.sessionId,
274
+ tool_definitions: toolDefinitions.length > 0 ? toolDefinitions : void 0
275
+ };
276
+ }
277
+ doGenerate(options) {
278
+ const run = async () => {
279
+ const requestId = uuidv4();
280
+ const url = `${this.apiUrl}/chat-stream`;
281
+ const payload = this.buildPayload(options);
282
+ this.log(`POST ${url}`);
283
+ if (this.debug && payload.tool_definitions) {
284
+ this.log(`Tools: ${payload.tool_definitions.map((t) => t.name).join(", ")}`);
285
+ }
286
+ const response = await fetch(url, {
287
+ method: "POST",
288
+ headers: this.getHeaders(requestId),
289
+ body: JSON.stringify(payload),
290
+ signal: options.abortSignal
291
+ });
292
+ if (!response.ok) {
293
+ const errorText = await response.text();
294
+ throw new Error(`Augment API error: ${response.status} ${response.statusText} - ${errorText}`);
295
+ }
296
+ if (!response.body) {
297
+ throw new Error("Response body is null");
298
+ }
299
+ const { content, usage, finishReason } = await this.parseStreamResponse(response.body);
300
+ return {
301
+ content,
302
+ finishReason,
303
+ usage,
304
+ warnings: []
305
+ };
306
+ };
307
+ return run();
308
+ }
309
+ /**
310
+ * Parse streaming response and collect content, usage, and finish reason
311
+ */
312
+ async parseStreamResponse(body) {
313
+ const reader = body.getReader();
314
+ const decoder = new TextDecoder();
315
+ let textBuffer = "";
316
+ let accumulatedText = "";
317
+ const content = [];
318
+ let usage = { inputTokens: void 0, outputTokens: void 0, totalTokens: void 0 };
319
+ let stopReason;
320
+ const toolCallsEmitted = /* @__PURE__ */ new Set();
321
+ try {
322
+ while (true) {
323
+ const { done, value } = await reader.read();
324
+ if (done) break;
325
+ textBuffer += decoder.decode(value, { stream: true });
326
+ while (textBuffer.includes("\n")) {
327
+ const newLineIndex = textBuffer.indexOf("\n");
328
+ const line = textBuffer.substring(0, newLineIndex);
329
+ textBuffer = textBuffer.substring(newLineIndex + 1);
330
+ const trimmed = line.trim();
331
+ if (trimmed) {
332
+ try {
333
+ const chunk = JSON.parse(trimmed);
334
+ if (chunk.text) {
335
+ accumulatedText += chunk.text;
336
+ }
337
+ if (chunk.nodes) {
338
+ for (const node of chunk.nodes) {
339
+ if (node.type === 5 /* TOOL_USE */ && node.tool_use) {
340
+ if (!toolCallsEmitted.has(node.tool_use.tool_use_id)) {
341
+ toolCallsEmitted.add(node.tool_use.tool_use_id);
342
+ const toolContent = responseNodeToContent(node);
343
+ if (toolContent) {
344
+ content.push(toolContent);
345
+ }
346
+ }
347
+ } else if (node.type === 8 /* THINKING */) {
348
+ const thinkingContent = responseNodeToContent(node);
349
+ if (thinkingContent) {
350
+ content.push(thinkingContent);
351
+ }
352
+ } else if (node.type === 10 /* TOKEN_USAGE */ && node.token_usage) {
353
+ usage = {
354
+ inputTokens: node.token_usage.input_tokens,
355
+ outputTokens: node.token_usage.output_tokens,
356
+ totalTokens: (node.token_usage.input_tokens ?? 0) + (node.token_usage.output_tokens ?? 0) || void 0
357
+ };
358
+ }
359
+ }
360
+ }
361
+ if (chunk.stop_reason !== void 0) {
362
+ stopReason = chunk.stop_reason;
363
+ }
364
+ } catch {
365
+ if (this.debug) this.log(`JSON parse failed for line: ${trimmed}`);
366
+ }
367
+ }
368
+ }
369
+ }
370
+ const finalChunk = decoder.decode();
371
+ if (finalChunk) textBuffer += finalChunk;
372
+ if (textBuffer.trim()) {
373
+ try {
374
+ const chunk = JSON.parse(textBuffer.trim());
375
+ if (chunk.text) accumulatedText += chunk.text;
376
+ if (chunk.stop_reason !== void 0) stopReason = chunk.stop_reason;
377
+ } catch {
378
+ if (this.debug) this.log(`JSON parse failed for remaining: ${textBuffer.trim()}`);
379
+ }
380
+ }
381
+ } finally {
382
+ reader.releaseLock();
383
+ }
384
+ if (accumulatedText) {
385
+ content.unshift({ type: "text", text: accumulatedText });
386
+ }
387
+ return {
388
+ content,
389
+ usage,
390
+ finishReason: stopReasonToFinishReason(stopReason)
391
+ };
392
+ }
393
+ doStream(options) {
394
+ const requestId = uuidv4();
395
+ const url = `${this.apiUrl}/chat-stream`;
396
+ const payload = this.buildPayload(options);
397
+ this.log(`POST ${url} (streaming)`);
398
+ const stream = new ReadableStream({
399
+ start: async (controller) => {
400
+ try {
401
+ const response = await fetch(url, {
402
+ method: "POST",
403
+ headers: this.getHeaders(requestId),
404
+ body: JSON.stringify(payload),
405
+ signal: options.abortSignal
406
+ });
407
+ if (!response.ok) {
408
+ const errorText = await response.text();
409
+ throw new Error(`Augment API error: ${response.status} ${response.statusText} - ${errorText}`);
410
+ }
411
+ if (!response.body) {
412
+ throw new Error("Response body is null");
413
+ }
414
+ const reader = response.body.getReader();
415
+ const decoder = new TextDecoder();
416
+ let textBuffer = "";
417
+ let textStarted = false;
418
+ const textId = uuidv4();
419
+ let stopReason;
420
+ const toolCallsEmitted = /* @__PURE__ */ new Set();
421
+ let usage = { inputTokens: void 0, outputTokens: void 0, totalTokens: void 0 };
422
+ while (true) {
423
+ const { done, value } = await reader.read();
424
+ if (done) break;
425
+ textBuffer += decoder.decode(value, { stream: true });
426
+ while (textBuffer.includes("\n")) {
427
+ const newLineIndex = textBuffer.indexOf("\n");
428
+ const line = textBuffer.substring(0, newLineIndex);
429
+ textBuffer = textBuffer.substring(newLineIndex + 1);
430
+ const trimmed = line.trim();
431
+ if (trimmed) {
432
+ try {
433
+ const chunk = JSON.parse(trimmed);
434
+ if (chunk.text) {
435
+ if (!textStarted) {
436
+ controller.enqueue({ type: "text-start", id: textId });
437
+ textStarted = true;
438
+ }
439
+ controller.enqueue({ type: "text-delta", id: textId, delta: chunk.text });
440
+ }
441
+ if (chunk.nodes) {
442
+ for (const node of chunk.nodes) {
443
+ if (node.type === 5 /* TOOL_USE */ && node.tool_use) {
444
+ if (!toolCallsEmitted.has(node.tool_use.tool_use_id)) {
445
+ toolCallsEmitted.add(node.tool_use.tool_use_id);
446
+ const inputJson = node.tool_use.input_json || "{}";
447
+ controller.enqueue({
448
+ type: "tool-input-start",
449
+ id: node.tool_use.tool_use_id,
450
+ toolName: node.tool_use.tool_name
451
+ });
452
+ controller.enqueue({
453
+ type: "tool-input-delta",
454
+ id: node.tool_use.tool_use_id,
455
+ delta: inputJson
456
+ });
457
+ controller.enqueue({
458
+ type: "tool-input-end",
459
+ id: node.tool_use.tool_use_id
460
+ });
461
+ controller.enqueue({
462
+ type: "tool-call",
463
+ toolCallId: node.tool_use.tool_use_id,
464
+ toolName: node.tool_use.tool_name,
465
+ input: inputJson
466
+ });
467
+ }
468
+ } else if (node.type === 8 /* THINKING */ && node.thinking) {
469
+ const text = node.thinking.content || node.thinking.summary || "";
470
+ if (text) {
471
+ const reasoningId = uuidv4();
472
+ controller.enqueue({ type: "reasoning-start", id: reasoningId });
473
+ controller.enqueue({ type: "reasoning-delta", id: reasoningId, delta: text });
474
+ controller.enqueue({ type: "reasoning-end", id: reasoningId });
475
+ }
476
+ } else if (node.type === 10 /* TOKEN_USAGE */ && node.token_usage) {
477
+ usage = {
478
+ inputTokens: node.token_usage.input_tokens,
479
+ outputTokens: node.token_usage.output_tokens,
480
+ totalTokens: (node.token_usage.input_tokens ?? 0) + (node.token_usage.output_tokens ?? 0) || void 0
481
+ };
482
+ }
483
+ }
484
+ }
485
+ if (chunk.stop_reason !== void 0) {
486
+ stopReason = chunk.stop_reason;
487
+ }
488
+ } catch {
489
+ if (this.debug) this.log(`JSON parse failed: ${trimmed}`);
490
+ }
491
+ }
492
+ }
493
+ }
494
+ if (textStarted) {
495
+ controller.enqueue({ type: "text-end", id: textId });
496
+ }
497
+ controller.enqueue({
498
+ type: "finish",
499
+ usage,
500
+ finishReason: stopReasonToFinishReason(stopReason)
501
+ });
502
+ controller.close();
503
+ } catch (error) {
504
+ controller.enqueue({ type: "error", error });
505
+ controller.error(error);
506
+ }
507
+ }
508
+ });
509
+ return Promise.resolve({ stream });
510
+ }
511
+ supportsImageUrls = false;
512
+ supportsStructuredOutputs = false;
513
+ supportedUrls = {};
514
+ }
515
+ export {
516
+ AugmentLanguageModel,
517
+ resolveAugmentCredentials
518
+ };
@@ -68,7 +68,7 @@ class DirectContext {
68
68
  */
69
69
  static async create(options = {}) {
70
70
  const { apiKey, apiUrl } = await resolveCredentials(options);
71
- return new DirectContext(apiKey, apiUrl, options.debug ?? false);
71
+ return new DirectContext(apiKey, apiUrl, options.debug ?? false, options.clientUserAgent);
72
72
  }
73
73
  /**
74
74
  * Import a DirectContext instance from a saved state object
@@ -79,7 +79,7 @@ class DirectContext {
79
79
  */
80
80
  static async import(state, options = {}) {
81
81
  const { apiKey, apiUrl } = await resolveCredentials(options);
82
- const instance = new DirectContext(apiKey, apiUrl, options.debug ?? false);
82
+ const instance = new DirectContext(apiKey, apiUrl, options.debug ?? false, options.clientUserAgent);
83
83
  await instance.doImport(state);
84
84
  return instance;
85
85
  }
@@ -101,12 +101,13 @@ class DirectContext {
101
101
  * @param apiUrl API URL for the tenant
102
102
  * @param debug Enable debug logging
103
103
  */
104
- constructor(apiKey, apiUrl, debug) {
104
+ constructor(apiKey, apiUrl, debug, clientUserAgent) {
105
105
  this.debug = debug;
106
106
  this.apiClient = new ContextAPIClient({
107
107
  apiKey,
108
108
  apiUrl,
109
- debug
109
+ debug,
110
+ clientUserAgent
110
111
  });
111
112
  this.blobCalculator = new BlobNameCalculator(
112
113
  DirectContext.MAX_FILE_SIZE_BYTES
@@ -16,6 +16,7 @@ declare class FileSystemContext {
16
16
  private readonly debug;
17
17
  private readonly apiKey;
18
18
  private readonly apiUrl;
19
+ private readonly clientUserAgent;
19
20
  private mcpClient;
20
21
  private apiClient;
21
22
  /**
@@ -9,6 +9,7 @@ class FileSystemContext {
9
9
  debug;
10
10
  apiKey;
11
11
  apiUrl;
12
+ clientUserAgent;
12
13
  mcpClient = null;
13
14
  apiClient = null;
14
15
  /**
@@ -23,6 +24,7 @@ class FileSystemContext {
23
24
  this.debug = options.debug ?? false;
24
25
  this.apiKey = apiKey;
25
26
  this.apiUrl = apiUrl;
27
+ this.clientUserAgent = options.clientUserAgent;
26
28
  }
27
29
  /**
28
30
  * Create and initialize a new FileSystemContext instance
@@ -172,7 +174,8 @@ class FileSystemContext {
172
174
  this.apiClient = new ContextAPIClient({
173
175
  apiKey: this.apiKey,
174
176
  apiUrl: this.apiUrl,
175
- debug: this.debug
177
+ debug: this.debug,
178
+ clientUserAgent: this.clientUserAgent
176
179
  });
177
180
  }
178
181
  return await chatWithRetry(this.apiClient, llmPrompt, this.debug);
@@ -37,11 +37,13 @@ type ContextAPIClientOptions = {
37
37
  apiKey: string;
38
38
  apiUrl: string;
39
39
  debug?: boolean;
40
+ /**
41
+ * Custom User-Agent string to use instead of the default SDK User-Agent.
42
+ * If not provided, defaults to "augment.sdk.context/{version} (typescript)".
43
+ * Example: "context-connectors/0.1.3 via:cli-search"
44
+ */
45
+ clientUserAgent?: string;
40
46
  };
41
- /**
42
- * Get user agent string for Context API requests
43
- */
44
- declare function getUserAgent(): string;
45
47
  /**
46
48
  * API client for Context operations
47
49
  */
@@ -50,6 +52,7 @@ declare class ContextAPIClient {
50
52
  private readonly apiUrl;
51
53
  private readonly sessionId;
52
54
  private readonly debug;
55
+ private readonly userAgent;
53
56
  constructor(options: ContextAPIClientOptions);
54
57
  private log;
55
58
  createRequestId(): string;
@@ -76,4 +79,4 @@ declare class ContextAPIClient {
76
79
  chat(prompt: string): Promise<string>;
77
80
  }
78
81
 
79
- export { APIError, type AgentCodebaseRetrievalResult, type BatchUploadResult, type CheckpointBlobsResult, ContextAPIClient, type ContextAPIClientOptions, type FindMissingResult, type UploadBlob, getUserAgent };
82
+ export { APIError, type AgentCodebaseRetrievalResult, type BatchUploadResult, type CheckpointBlobsResult, ContextAPIClient, type ContextAPIClientOptions, type FindMissingResult, type UploadBlob };
@@ -11,19 +11,18 @@ class APIError extends Error {
11
11
  this.statusText = statusText;
12
12
  }
13
13
  }
14
- function getUserAgent() {
15
- return `augment.sdk.context/${getSDKVersion()} (typescript)`;
16
- }
17
14
  class ContextAPIClient {
18
15
  apiKey;
19
16
  apiUrl;
20
17
  sessionId;
21
18
  debug;
19
+ userAgent;
22
20
  constructor(options) {
23
21
  this.apiKey = options.apiKey;
24
22
  this.apiUrl = options.apiUrl;
25
23
  this.sessionId = uuidv4();
26
24
  this.debug = options.debug ?? false;
25
+ this.userAgent = options.clientUserAgent?.trim() || `augment.sdk.context/${getSDKVersion()} (typescript)`;
27
26
  }
28
27
  log(message) {
29
28
  if (this.debug) {
@@ -46,7 +45,7 @@ class ContextAPIClient {
46
45
  Authorization: `Bearer ${this.apiKey}`,
47
46
  "X-Request-Session-Id": this.sessionId,
48
47
  "X-Request-Id": requestId,
49
- "User-Agent": getUserAgent()
48
+ "User-Agent": this.userAgent
50
49
  },
51
50
  body: JSON.stringify(payload)
52
51
  });
@@ -219,7 +218,7 @@ class ContextAPIClient {
219
218
  "X-Request-Id": requestId,
220
219
  "conversation-id": this.sessionId,
221
220
  "X-Mode": "sdk",
222
- "User-Agent": getUserAgent()
221
+ "User-Agent": this.userAgent
223
222
  },
224
223
  body: JSON.stringify(payload)
225
224
  });
@@ -242,6 +241,5 @@ class ContextAPIClient {
242
241
  }
243
242
  export {
244
243
  APIError,
245
- ContextAPIClient,
246
- getUserAgent
244
+ ContextAPIClient
247
245
  };
@@ -162,6 +162,12 @@ type DirectContextOptions = {
162
162
  * Default: false
163
163
  */
164
164
  debug?: boolean;
165
+ /**
166
+ * Custom User-Agent string to use instead of the default SDK User-Agent.
167
+ * If not provided, defaults to "augment.sdk.context/{version} (typescript)".
168
+ * Example: "context-connectors/0.1.3 via:cli-search"
169
+ */
170
+ clientUserAgent?: string;
165
171
  };
166
172
  /**
167
173
  * Full state for Direct Context with all blob information
@@ -227,6 +233,12 @@ type FileSystemContextOptions = {
227
233
  auggiePath?: string;
228
234
  /** Enable debug logging */
229
235
  debug?: boolean;
236
+ /**
237
+ * Custom User-Agent string to use instead of the default SDK User-Agent.
238
+ * If not provided, defaults to "augment.sdk.context/{version} (typescript)".
239
+ * Example: "context-connectors/0.1.3 via:mcp"
240
+ */
241
+ clientUserAgent?: string;
230
242
  };
231
243
 
232
244
  export type { AddToIndexOptions, BlobEntry, BlobInfo, Blobs, Chunk, DirectContextOptions, DirectContextState, ExportOptions, File, FileSystemContextOptions, FullContextState, IndexingProgress, IndexingResult, SearchOnlyContextState, SearchResult };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { Auggie, PredefinedToolType, ToolIdentifier } from './auggie/sdk-acp-client.js';
2
+ export { AugmentCredentials, AugmentLanguageModel, AugmentLanguageModelConfig, resolveAugmentCredentials } from './auggie/ai-sdk-provider.js';
2
3
  export { DirectContext } from './context/direct-context.js';
3
4
  export { FileSystemContext } from './context/filesystem-context.js';
4
5
  export { APIError } from './context/internal/api-client.js';
@@ -6,3 +7,5 @@ export { BlobTooLargeError } from './context/internal/blob-name-calculator.js';
6
7
  export { AddToIndexOptions, BlobEntry, BlobInfo, Blobs, DirectContextOptions, DirectContextState, ExportOptions, File, FileSystemContextOptions, FullContextState, IndexingProgress, IndexingResult, SearchOnlyContextState } from './context/types.js';
7
8
  import '@agentclientprotocol/sdk';
8
9
  import 'ai';
10
+ import '@ai-sdk/provider';
11
+ import './context/internal/credentials.js';
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  import {
2
2
  Auggie
3
3
  } from "./auggie/sdk-acp-client.js";
4
+ import {
5
+ AugmentLanguageModel,
6
+ resolveAugmentCredentials
7
+ } from "./auggie/ai-sdk-provider.js";
4
8
  import { DirectContext } from "./context/direct-context.js";
5
9
  import { FileSystemContext } from "./context/filesystem-context.js";
6
10
  import { APIError } from "./context/internal/api-client.js";
@@ -8,7 +12,9 @@ import { BlobTooLargeError } from "./context/internal/blob-name-calculator.js";
8
12
  export {
9
13
  APIError,
10
14
  Auggie,
15
+ AugmentLanguageModel,
11
16
  BlobTooLargeError,
12
17
  DirectContext,
13
- FileSystemContext
18
+ FileSystemContext,
19
+ resolveAugmentCredentials
14
20
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@augmentcode/auggie-sdk",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "TypeScript SDK for Auggie",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,10 +35,11 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@agentclientprotocol/sdk": "^0.5.1",
38
+ "@ai-sdk/provider": "^3.0.3",
38
39
  "@mastra/mcp": "^0.14.1",
39
40
  "ai": "^5.0.86",
40
41
  "async-mutex": "^0.5.0",
41
- "zod": "^4.1.12",
42
- "uuid": "^11.1.0"
42
+ "uuid": "^11.1.0",
43
+ "zod": "^4.1.12"
43
44
  }
44
45
  }