@sandagent/sdk 0.2.2 → 0.2.3
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.js +16 -12
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +1 -5
- package/dist/react/index.js +1 -7
- package/dist/react/index.js.map +1 -1
- package/package.json +4 -5
package/dist/index.js
CHANGED
|
@@ -62,7 +62,8 @@ function createEmptyUsage() {
|
|
|
62
62
|
total: 0,
|
|
63
63
|
text: void 0,
|
|
64
64
|
reasoning: void 0
|
|
65
|
-
}
|
|
65
|
+
},
|
|
66
|
+
raw: void 0
|
|
66
67
|
};
|
|
67
68
|
}
|
|
68
69
|
var SandAgentLanguageModel = class {
|
|
@@ -321,7 +322,7 @@ var SandAgentLanguageModel = class {
|
|
|
321
322
|
type: "text-start",
|
|
322
323
|
id: parsed.id,
|
|
323
324
|
providerMetadata: {
|
|
324
|
-
|
|
325
|
+
sandagent: {
|
|
325
326
|
sessionId: this.sessionId
|
|
326
327
|
}
|
|
327
328
|
}
|
|
@@ -403,10 +404,8 @@ var SandAgentLanguageModel = class {
|
|
|
403
404
|
} else {
|
|
404
405
|
finishReason = this.mapFinishReason(rawFinishReason);
|
|
405
406
|
}
|
|
406
|
-
const rawUsage = parsed.
|
|
407
|
-
const usage = this.convertUsage(
|
|
408
|
-
rawUsage
|
|
409
|
-
);
|
|
407
|
+
const { usage: rawUsage } = parsed.messageMetadata;
|
|
408
|
+
const usage = this.convertUsage(rawUsage);
|
|
410
409
|
parts.push({
|
|
411
410
|
type: "finish",
|
|
412
411
|
finishReason,
|
|
@@ -487,6 +486,7 @@ var SandAgentLanguageModel = class {
|
|
|
487
486
|
if ("inputTokens" in data && "outputTokens" in data) {
|
|
488
487
|
const inputTokens = data.inputTokens;
|
|
489
488
|
const outputTokens = data.outputTokens;
|
|
489
|
+
const rawData = "raw" in data ? data.raw : data;
|
|
490
490
|
return {
|
|
491
491
|
inputTokens: {
|
|
492
492
|
total: inputTokens.total ?? 0,
|
|
@@ -496,9 +496,10 @@ var SandAgentLanguageModel = class {
|
|
|
496
496
|
},
|
|
497
497
|
outputTokens: {
|
|
498
498
|
total: outputTokens.total ?? 0,
|
|
499
|
-
text: void 0,
|
|
500
|
-
reasoning: void 0
|
|
501
|
-
}
|
|
499
|
+
text: outputTokens.text ?? outputTokens.textTokens ?? void 0,
|
|
500
|
+
reasoning: outputTokens.reasoning ?? outputTokens.reasoningTokens ?? void 0
|
|
501
|
+
},
|
|
502
|
+
raw: rawData
|
|
502
503
|
};
|
|
503
504
|
}
|
|
504
505
|
const usage = data.usage ?? data;
|
|
@@ -507,6 +508,8 @@ var SandAgentLanguageModel = class {
|
|
|
507
508
|
const outputTokens = usage.output_tokens ?? 0;
|
|
508
509
|
const cacheWrite = usage.cache_creation_input_tokens ?? 0;
|
|
509
510
|
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
|
511
|
+
const textTokens = usage.text_tokens ?? void 0;
|
|
512
|
+
const reasoningTokens = usage.reasoning_tokens ?? void 0;
|
|
510
513
|
return {
|
|
511
514
|
inputTokens: {
|
|
512
515
|
total: inputTokens + cacheWrite + cacheRead,
|
|
@@ -516,9 +519,10 @@ var SandAgentLanguageModel = class {
|
|
|
516
519
|
},
|
|
517
520
|
outputTokens: {
|
|
518
521
|
total: outputTokens,
|
|
519
|
-
text:
|
|
520
|
-
reasoning:
|
|
521
|
-
}
|
|
522
|
+
text: textTokens,
|
|
523
|
+
reasoning: reasoningTokens
|
|
524
|
+
},
|
|
525
|
+
raw: usage
|
|
522
526
|
};
|
|
523
527
|
}
|
|
524
528
|
return createEmptyUsage();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider/sandagent-provider.ts","../src/provider/sandagent-language-model.ts","../src/provider/types.ts","../src/index.ts"],"sourcesContent":["import type {\n EmbeddingModelV3,\n ImageModelV3,\n LanguageModelV3,\n ProviderV3,\n} from \"@ai-sdk/provider\";\nimport { NoSuchModelError } from \"@ai-sdk/provider\";\nimport type { RunnerSpec } from \"@sandagent/manager\";\nimport { SandAgentLanguageModel } from \"./sandagent-language-model\";\nimport type { Logger, SandAgentModelId } from \"./types\";\nimport {\n type SandAgentProviderSettings,\n getRunnerKindForModel,\n resolveModelId,\n} from \"./types\";\n\nexport type { SandAgentProviderSettings } from \"./types\";\n\n/**\n * SandAgent provider interface that extends the AI SDK's ProviderV3.\n */\nexport interface SandAgentProvider extends ProviderV3 {\n (\n modelId: SandAgentModelId,\n options?: Partial<SandAgentProviderSettings>,\n ): LanguageModelV3;\n\n languageModel(\n modelId: SandAgentModelId,\n options?: Partial<SandAgentProviderSettings>,\n ): LanguageModelV3;\n\n chat(\n modelId: SandAgentModelId,\n options?: Partial<SandAgentProviderSettings>,\n ): LanguageModelV3;\n\n embeddingModel(modelId: string): EmbeddingModelV3;\n textEmbeddingModel(modelId: string): EmbeddingModelV3;\n imageModel(modelId: string): ImageModelV3;\n}\n\nfunction getLogger(settings: Partial<SandAgentProviderSettings>): Logger {\n if (settings.logger === false) {\n return {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n };\n }\n\n if (settings.logger) {\n return settings.logger;\n }\n\n const isVerbose = settings.verbose ?? false;\n return {\n debug: (msg) => isVerbose && console.debug(msg),\n info: (msg) => isVerbose && console.info(msg),\n warn: (msg) => console.warn(msg),\n error: (msg) => console.error(msg),\n };\n}\n\n/**\n * Creates a SandAgent provider instance with the specified configuration.\n *\n * @example\n * ```typescript\n * import { createSandAgent } from '@sandagent/sdk';\n * import { E2BSandbox } from '@sandagent/sandbox-e2b';\n * import { generateText } from 'ai';\n *\n * const sandagent = createSandAgent({\n * sandbox: new E2BSandbox({ apiKey: process.env.E2B_API_KEY! }),\n * env: {\n * ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,\n * },\n * });\n *\n * const { text } = await generateText({\n * model: sandagent('sonnet'),\n * prompt: 'Create a hello world program',\n * });\n * ```\n */\nexport function createSandAgent(\n defaultOptions: SandAgentProviderSettings,\n): SandAgentProvider {\n const logger = getLogger(defaultOptions);\n\n if (!defaultOptions.sandbox) {\n throw new Error(\n \"SandAgent provider requires a sandbox adapter. \" +\n \"Please provide one, e.g.: new E2BSandbox({ apiKey: 'xxx' })\",\n );\n }\n\n const createModel = (\n modelId: SandAgentModelId,\n options: Partial<SandAgentProviderSettings> = {},\n ): LanguageModelV3 => {\n const runnerKind = getRunnerKindForModel(modelId);\n const resolvedModelId = resolveModelId(modelId);\n\n const runner: RunnerSpec = {\n kind: runnerKind,\n model: resolvedModelId,\n outputFormat: \"stream\",\n };\n\n const mergedOptions = {\n ...defaultOptions,\n ...options,\n runner,\n env: {\n ...defaultOptions.env,\n ...options.env,\n },\n artifactProcessors: [\n ...(defaultOptions.artifactProcessors ?? []),\n ...(options.artifactProcessors ?? []),\n ],\n } as SandAgentProviderSettings & { runner: RunnerSpec };\n\n logger.debug(\n `[sandagent] Creating model: ${modelId} with runner: ${runner.kind}`,\n );\n\n return new SandAgentLanguageModel({\n id: modelId,\n options: mergedOptions,\n });\n };\n\n const provider = function (\n modelId: SandAgentModelId,\n options?: Partial<SandAgentProviderSettings>,\n ) {\n if (new.target) {\n throw new Error(\n \"The SandAgent model function cannot be called with the new keyword.\",\n );\n }\n\n return createModel(modelId, options);\n };\n\n provider.languageModel = createModel;\n provider.chat = createModel;\n provider.specificationVersion = \"v3\" as const;\n\n provider.embeddingModel = (modelId: string): EmbeddingModelV3 => {\n throw new NoSuchModelError({\n modelId,\n modelType: \"embeddingModel\",\n });\n };\n\n provider.textEmbeddingModel = (modelId: string): EmbeddingModelV3 => {\n throw new NoSuchModelError({\n modelId,\n modelType: \"embeddingModel\",\n });\n };\n\n provider.imageModel = (modelId: string): ImageModelV3 => {\n throw new NoSuchModelError({\n modelId,\n modelType: \"imageModel\",\n });\n };\n\n return provider as SandAgentProvider;\n}\n","import type {\n JSONValue,\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Content,\n LanguageModelV3FinishReason,\n LanguageModelV3GenerateResult,\n LanguageModelV3Prompt,\n LanguageModelV3StreamPart,\n LanguageModelV3StreamResult,\n LanguageModelV3Usage,\n SharedV3ProviderMetadata,\n SharedV3Warning,\n} from \"@ai-sdk/provider\";\nimport { type Message, type RunnerSpec, SandAgent } from \"@sandagent/manager\";\nimport type {\n Logger,\n SandAgentModelId,\n SandAgentProviderSettings,\n} from \"./types\";\nimport { resolveModelId } from \"./types\";\n\n/**\n * Options for creating a SandAgent language model instance.\n */\nexport interface SandAgentLanguageModelOptions {\n id: SandAgentModelId;\n options: SandAgentProviderSettings & { runner: RunnerSpec };\n}\n\nfunction getLogger(settings: SandAgentProviderSettings): Logger {\n if (settings.logger === false) {\n return {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n };\n }\n\n if (settings.logger) {\n return settings.logger;\n }\n\n const isVerbose = settings.verbose ?? false;\n return {\n debug: (msg) => isVerbose && console.debug(msg),\n info: (msg) => isVerbose && console.info(msg),\n warn: (msg) => console.warn(msg),\n error: (msg) => console.error(msg),\n };\n}\n\nfunction createEmptyUsage(): LanguageModelV3Usage {\n return {\n inputTokens: {\n total: 0,\n noCache: 0,\n cacheRead: 0,\n cacheWrite: 0,\n },\n outputTokens: {\n total: 0,\n text: undefined,\n reasoning: undefined,\n },\n };\n}\n\n/**\n * SandAgent Language Model implementation for AI SDK.\n */\nexport class SandAgentLanguageModel implements LanguageModelV3 {\n readonly specificationVersion = \"v3\" as const;\n readonly provider = \"sandagent\";\n readonly modelId: string;\n readonly supportedUrls: Record<string, RegExp[]> = {\n \"image/*\": [/.*/],\n };\n\n private readonly options: SandAgentProviderSettings & { runner: RunnerSpec };\n private readonly logger: Logger;\n private sessionId: string | undefined;\n private toolNameMap: Map<string, string> = new Map();\n\n constructor(modelOptions: SandAgentLanguageModelOptions) {\n this.modelId = resolveModelId(modelOptions.id);\n this.options = modelOptions.options;\n this.logger = getLogger(modelOptions.options);\n }\n\n async doGenerate(\n options: LanguageModelV3CallOptions,\n ): Promise<LanguageModelV3GenerateResult> {\n const { stream, request } = await this.doStream(options);\n const reader = stream.getReader();\n\n const content: LanguageModelV3Content[] = [];\n const warnings: SharedV3Warning[] = [];\n let finishReason: LanguageModelV3FinishReason = {\n unified: \"other\",\n raw: undefined,\n };\n let usage: LanguageModelV3Usage = createEmptyUsage();\n let providerMetadata: SharedV3ProviderMetadata | undefined;\n\n const textParts: Map<string, { text: string }> = new Map();\n const toolInputs: Map<string, { toolName: string; input: string }> =\n new Map();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n switch (value.type) {\n case \"text-start\": {\n textParts.set(value.id, { text: \"\" });\n break;\n }\n case \"text-delta\": {\n const part = textParts.get(value.id);\n if (part) {\n part.text += value.delta;\n }\n break;\n }\n case \"text-end\": {\n const part = textParts.get(value.id);\n if (part) {\n content.push({\n type: \"text\",\n text: part.text,\n });\n }\n break;\n }\n case \"tool-input-start\": {\n toolInputs.set(value.id, { toolName: value.toolName, input: \"\" });\n break;\n }\n case \"tool-input-delta\": {\n const tool = toolInputs.get(value.id);\n if (tool) {\n tool.input += value.delta;\n }\n break;\n }\n case \"tool-input-end\": {\n break;\n }\n case \"tool-call\": {\n content.push({\n type: \"tool-call\",\n toolCallId: value.toolCallId,\n toolName: value.toolName,\n input: value.input,\n providerExecuted: value.providerExecuted,\n });\n break;\n }\n case \"stream-start\": {\n warnings.push(...value.warnings);\n break;\n }\n case \"finish\": {\n finishReason = value.finishReason;\n usage = value.usage;\n providerMetadata = value.providerMetadata;\n break;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n return {\n content,\n finishReason,\n usage,\n providerMetadata,\n request,\n warnings,\n };\n }\n\n async doStream(\n options: LanguageModelV3CallOptions,\n ): Promise<LanguageModelV3StreamResult> {\n const { prompt, abortSignal } = options;\n const messages = this.convertPromptToMessages(prompt);\n\n this.logger.debug(\n `[sandagent] Starting stream with ${messages.length} messages`,\n );\n\n const sandbox = this.options.sandbox;\n const sandboxEnv = sandbox.getEnv?.() ?? {};\n const sandboxWorkdir =\n this.options.cwd ?? sandbox.getWorkdir?.() ?? \"/workspace\";\n\n const agent = new SandAgent({\n sandbox: this.options.sandbox,\n runner: this.options.runner,\n env: { ...sandboxEnv, ...this.options.env },\n });\n\n try {\n const stream = await agent.stream({\n messages,\n workspace: {\n path: sandboxWorkdir,\n },\n resume: this.options.resume,\n signal: abortSignal,\n });\n\n const self = this;\n const reader = stream.getReader();\n\n if (!reader) {\n throw new Error(\"Response body is not readable\");\n }\n\n const outputStream = new ReadableStream<LanguageModelV3StreamPart>({\n async start(controller) {\n try {\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n if (buffer.trim()) {\n const parts = self.parseSSEBuffer(buffer);\n for (const part of parts) {\n controller.enqueue(part);\n }\n }\n controller.close();\n break;\n }\n\n const text = new TextDecoder().decode(value);\n buffer += text;\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n let foundDone = false;\n for (const line of lines) {\n if (line.startsWith(\"data: \")) {\n const data = line.slice(6);\n\n if (data === \"[DONE]\") {\n foundDone = true;\n continue;\n }\n try {\n const parts = self.parseSSEData(data);\n for (const part of parts) {\n controller.enqueue(part);\n\n if (\n self.options.artifactProcessors?.length &&\n self.sessionId\n ) {\n const sessionId: string = self.sessionId;\n for (const processor of self.options\n .artifactProcessors) {\n Promise.resolve()\n .then(() => processor.onChange(part, sessionId))\n .catch((e) => {\n self.logger.error(\n `[sandagent] Artifact processor error: ${e}`,\n );\n });\n }\n }\n }\n } catch (e) {\n self.logger.error(\n `[sandagent] Failed to parse SSE data: ${e}`,\n );\n }\n }\n }\n\n if (foundDone) {\n controller.close();\n return;\n }\n }\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n self.logger.info(\"[sandagent] Stream aborted by user\");\n } else {\n self.logger.error(`[sandagent] Stream error: ${error}`);\n }\n controller.error(error);\n }\n },\n\n cancel() {\n reader.cancel();\n },\n });\n\n return {\n stream: outputStream,\n request: {\n body: JSON.stringify({ messages }),\n },\n };\n } catch (error) {\n await agent.destroy().catch(() => {});\n throw error;\n }\n }\n\n private parseSSEBuffer(buffer: string): LanguageModelV3StreamPart[] {\n const parts: LanguageModelV3StreamPart[] = [];\n const lines = buffer.split(\"\\n\");\n\n for (const line of lines) {\n if (line.startsWith(\"data: \")) {\n const data = line.slice(6);\n\n if (data === \"[DONE]\") {\n continue;\n }\n\n try {\n const parsedParts = this.parseSSEData(data);\n parts.push(...parsedParts);\n } catch (e) {\n this.logger.error(`[sandagent] Failed to parse SSE data: ${e}`);\n }\n }\n }\n\n return parts;\n }\n\n private parseSSEData(data: string): LanguageModelV3StreamPart[] {\n const parts: LanguageModelV3StreamPart[] = [];\n const parsed = JSON.parse(data) as Record<string, unknown>;\n\n switch (parsed.type) {\n case \"start\": {\n break;\n }\n\n case \"message-metadata\": {\n const metadata = parsed.messageMetadata as Record<string, unknown>;\n if (metadata?.sessionId && typeof metadata.sessionId === \"string\") {\n this.sessionId = metadata.sessionId;\n this.logger.debug(\n `[sandagent] Session ID extracted: ${this.sessionId}`,\n );\n parts.push({\n type: \"raw\",\n rawValue: this.sessionId,\n });\n }\n break;\n }\n\n case \"text-start\": {\n parts.push({\n type: \"text-start\",\n id: parsed.id as string,\n providerMetadata: {\n \"claude-code\": {\n sessionId: this.sessionId,\n },\n },\n });\n break;\n }\n\n case \"text-delta\": {\n parts.push({\n type: \"text-delta\",\n id: parsed.id as string,\n delta: parsed.delta as string,\n });\n break;\n }\n\n case \"text-end\": {\n parts.push({\n type: \"text-end\",\n id: parsed.id as string,\n });\n break;\n }\n\n case \"tool-input-start\": {\n parts.push({\n type: \"tool-input-start\",\n id: parsed.toolCallId as string,\n toolName: parsed.toolName as string,\n dynamic: parsed.dynamic as boolean,\n providerExecuted: parsed.providerExecuted as boolean,\n });\n break;\n }\n\n case \"tool-input-delta\": {\n parts.push({\n type: \"tool-input-delta\",\n id: parsed.toolCallId as string,\n delta: parsed.inputTextDelta as string,\n });\n break;\n }\n case \"tool-input-available\": {\n const toolCallId = parsed.toolCallId as string;\n const toolName = parsed.toolName as string;\n const input = parsed.input as Record<string, unknown>;\n this.toolNameMap.set(toolCallId, toolName);\n parts.push({\n type: \"tool-call\",\n toolCallId,\n toolName,\n input: JSON.stringify(input),\n dynamic: parsed.dynamic as boolean,\n providerExecuted: parsed.providerExecuted as boolean,\n });\n break;\n }\n\n case \"tool-output-available\": {\n const toolName = this.toolNameMap.get(parsed.toolCallId as string);\n parts.push({\n type: \"tool-result\",\n toolCallId: parsed.toolCallId as string,\n toolName: toolName ?? \"\",\n result: parsed.output as NonNullable<JSONValue>,\n isError: parsed.isError as boolean,\n dynamic: parsed.dynamic as boolean,\n });\n break;\n }\n case \"error\": {\n parts.push({\n type: \"error\",\n error: new Error(parsed.errorText as string),\n });\n break;\n }\n\n case \"finish\": {\n const rawFinishReason = parsed.finishReason;\n let finishReason: LanguageModelV3FinishReason;\n\n if (\n typeof rawFinishReason === \"object\" &&\n rawFinishReason !== null &&\n \"unified\" in rawFinishReason\n ) {\n finishReason = rawFinishReason as LanguageModelV3FinishReason;\n } else {\n finishReason = this.mapFinishReason(rawFinishReason as string);\n }\n\n const rawUsage = parsed.usage ?? parsed.messageMetadata;\n const usage = this.convertUsage(\n rawUsage as Record<string, unknown> | undefined,\n );\n\n parts.push({\n type: \"finish\",\n finishReason,\n usage,\n providerMetadata: {\n sandagent: parsed.messageMetadata,\n } as SharedV3ProviderMetadata,\n });\n break;\n }\n }\n\n return parts;\n }\n\n private convertPromptToMessages(prompt: LanguageModelV3Prompt): Message[] {\n const messages: Message[] = [];\n\n for (const message of prompt) {\n switch (message.role) {\n case \"system\": {\n messages.push({\n role: \"system\",\n content: message.content,\n });\n break;\n }\n\n case \"user\": {\n const textParts = message.content\n .filter(\n (part): part is { type: \"text\"; text: string } =>\n part.type === \"text\",\n )\n .map((part) => part.text);\n\n if (textParts.length > 0) {\n messages.push({\n role: \"user\",\n content: textParts.join(\"\\n\"),\n });\n }\n break;\n }\n\n case \"assistant\": {\n const textParts = message.content\n .filter(\n (part): part is { type: \"text\"; text: string } =>\n part.type === \"text\",\n )\n .map((part) => part.text);\n\n if (textParts.length > 0) {\n messages.push({\n role: \"assistant\",\n content: textParts.join(\"\\n\"),\n });\n }\n break;\n }\n\n case \"tool\": {\n break;\n }\n }\n }\n\n return messages;\n }\n\n private mapFinishReason(\n reason: string | undefined,\n ): LanguageModelV3FinishReason {\n switch (reason) {\n case \"stop\":\n return { unified: \"stop\", raw: reason };\n case \"length\":\n return { unified: \"length\", raw: reason };\n case \"tool_calls\":\n case \"tool-calls\":\n return { unified: \"tool-calls\", raw: reason };\n case \"content_filter\":\n case \"content-filter\":\n return { unified: \"content-filter\", raw: reason };\n case \"error\":\n return { unified: \"error\", raw: reason };\n default:\n return { unified: \"other\", raw: reason ?? \"unknown\" };\n }\n }\n\n private convertUsage(\n data: Record<string, unknown> | undefined,\n ): LanguageModelV3Usage {\n if (!data) {\n return createEmptyUsage();\n }\n\n if (\"inputTokens\" in data && \"outputTokens\" in data) {\n const inputTokens = data.inputTokens as Record<string, number>;\n const outputTokens = data.outputTokens as Record<string, number>;\n\n return {\n inputTokens: {\n total: inputTokens.total ?? 0,\n noCache: inputTokens.noCache ?? 0,\n cacheRead: inputTokens.cacheRead ?? 0,\n cacheWrite: inputTokens.cacheWrite ?? 0,\n },\n outputTokens: {\n total: outputTokens.total ?? 0,\n text: undefined,\n reasoning: undefined,\n },\n };\n }\n\n const usage = (data.usage ?? data) as Record<string, number>;\n\n if (\"input_tokens\" in usage || \"output_tokens\" in usage) {\n const inputTokens = (usage.input_tokens as number) ?? 0;\n const outputTokens = (usage.output_tokens as number) ?? 0;\n const cacheWrite = (usage.cache_creation_input_tokens as number) ?? 0;\n const cacheRead = (usage.cache_read_input_tokens as number) ?? 0;\n\n return {\n inputTokens: {\n total: inputTokens + cacheWrite + cacheRead,\n noCache: inputTokens,\n cacheRead,\n cacheWrite,\n },\n outputTokens: {\n total: outputTokens,\n text: undefined,\n reasoning: undefined,\n },\n };\n }\n\n return createEmptyUsage();\n }\n}\n","import type { LanguageModelV3StreamPart } from \"@ai-sdk/provider\";\nimport type { SandAgentOptions } from \"@sandagent/manager\";\n\n/**\n * Artifact Processor 返回结果\n */\nexport interface ArtifactResult {\n artifactId: string;\n content: string;\n mimeType?: string;\n}\n\n/**\n * Stream writer interface for writing data parts\n */\nexport interface StreamWriter {\n write(chunk: {\n type: string;\n id?: string;\n data?: unknown;\n transient?: boolean;\n }): void;\n}\n\n/**\n * Artifact Processor 接口\n */\nexport interface ArtifactProcessor {\n /**\n * 当收到 stream part 时触发\n * @param event - Stream part 事件\n * @param sessionId - 当前会话 ID(taskId)\n */\n onChange(event: LanguageModelV3StreamPart, sessionId: string): Promise<void>;\n}\n\n/**\n * Logger interface for custom logging.\n */\nexport interface Logger {\n debug: (message: string) => void;\n info: (message: string) => void;\n warn: (message: string) => void;\n error: (message: string) => void;\n}\n\n/**\n * AI Provider specific settings that extend SandAgentOptions.\n */\nexport interface SandAgentProviderSettings\n extends Omit<SandAgentOptions, \"runner\" | \"sandboxId\"> {\n /** Working directory for CLI operations inside the sandbox. */\n cwd?: string;\n /** Resume session ID for multi-turn conversation. */\n resume?: string;\n /** Enable verbose logging for debugging. */\n verbose?: boolean;\n /** Custom logger for handling warnings and errors. */\n logger?: Logger | false;\n /** Artifact processors for handling artifact events. */\n artifactProcessors?: ArtifactProcessor[];\n}\n\n/**\n * Supported model identifiers for SandAgent.\n */\nexport type SandAgentModelId =\n | \"claude-sonnet-4-20250514\"\n | \"claude-opus-4-20250514\"\n | \"claude-sonnet-4.5-20250514\"\n | \"claude-opus-4.5-20250514\"\n | \"claude-4-5-sonnet-20250514\"\n | \"claude-4-5-opus-20250514\"\n | \"claude-3-7-sonnet-20250219\"\n | \"claude-3-5-sonnet-20241022\"\n | \"claude-3-5-haiku-20241022\"\n | \"claude-3-opus-20240229\"\n | \"claude-3-sonnet-20240229\"\n | \"claude-3-haiku-20240307\"\n | \"sonnet\"\n | \"opus\"\n | \"haiku\"\n | (string & {});\n\n/**\n * Maps model aliases to full model IDs\n */\nexport function resolveModelId(modelId: SandAgentModelId): string {\n switch (modelId) {\n case \"sonnet\":\n return \"claude-sonnet-4-20250514\";\n case \"opus\":\n return \"claude-opus-4-20250514\";\n case \"haiku\":\n return \"claude-3-5-haiku-20241022\";\n default:\n return modelId;\n }\n}\n\n/**\n * Determine the runner kind based on model ID\n */\nexport function getRunnerKindForModel(\n modelId: SandAgentModelId,\n): \"claude-agent-sdk\" {\n const resolvedId = resolveModelId(modelId);\n\n if (\n resolvedId.startsWith(\"claude\") ||\n resolvedId.includes(\"anthropic\") ||\n resolvedId.startsWith(\"us.anthropic\")\n ) {\n return \"claude-agent-sdk\";\n }\n\n return \"claude-agent-sdk\";\n}\n","/**\n * @sandagent/sdk\n *\n * SandAgent SDK - AI Provider and React hooks for building AI chat interfaces.\n *\n * Main entry point exports the AI provider (backend).\n * React hooks are available via \"@sandagent/sdk/react\".\n *\n * @example\n * ```typescript\n * // Backend - Provider\n * import { createSandAgent } from \"@sandagent/sdk\";\n * const sandagent = createSandAgent({ sandbox, env });\n * const model = sandagent(\"sonnet\");\n *\n * // Frontend - React hooks\n * import { useSandAgentChat } from \"@sandagent/sdk/react\";\n * const { messages, sendMessage } = useSandAgentChat({ apiEndpoint: \"/api/ai\" });\n * ```\n */\n\n// Provider exports\nexport {\n createSandAgent,\n SandAgentLanguageModel,\n resolveModelId,\n} from \"./provider\";\n\nexport type {\n SandAgentProvider,\n SandAgentProviderSettings,\n SandAgentLanguageModelOptions,\n SandAgentModelId,\n Logger,\n ArtifactProcessor,\n ArtifactResult,\n StreamWriter,\n // Re-exports from @sandagent/manager\n SandboxAdapter,\n SandboxHandle,\n TranscriptEntry,\n Message,\n // Re-exports from @ai-sdk/provider\n LanguageModelV3StreamPart,\n} from \"./provider\";\n\n// Re-export LocalSandbox for convenience\nexport { LocalSandbox } from \"@sandagent/manager\";\nexport type { LocalSandboxOptions } from \"@sandagent/manager\";\n\nexport const VERSION = \"0.1.0\";\n"],"mappings":"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","names":["getLogger"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider/sandagent-provider.ts","../src/provider/sandagent-language-model.ts","../src/provider/types.ts","../src/index.ts"],"sourcesContent":["import type {\n EmbeddingModelV3,\n ImageModelV3,\n LanguageModelV3,\n ProviderV3,\n} from \"@ai-sdk/provider\";\nimport { NoSuchModelError } from \"@ai-sdk/provider\";\nimport type { RunnerSpec } from \"@sandagent/manager\";\nimport { SandAgentLanguageModel } from \"./sandagent-language-model\";\nimport type { Logger, SandAgentModelId } from \"./types\";\nimport {\n type SandAgentProviderSettings,\n getRunnerKindForModel,\n resolveModelId,\n} from \"./types\";\n\nexport type { SandAgentProviderSettings } from \"./types\";\n\n/**\n * SandAgent provider interface that extends the AI SDK's ProviderV3.\n */\nexport interface SandAgentProvider extends ProviderV3 {\n (\n modelId: SandAgentModelId,\n options?: Partial<SandAgentProviderSettings>,\n ): LanguageModelV3;\n\n languageModel(\n modelId: SandAgentModelId,\n options?: Partial<SandAgentProviderSettings>,\n ): LanguageModelV3;\n\n chat(\n modelId: SandAgentModelId,\n options?: Partial<SandAgentProviderSettings>,\n ): LanguageModelV3;\n\n embeddingModel(modelId: string): EmbeddingModelV3;\n textEmbeddingModel(modelId: string): EmbeddingModelV3;\n imageModel(modelId: string): ImageModelV3;\n}\n\nfunction getLogger(settings: Partial<SandAgentProviderSettings>): Logger {\n if (settings.logger === false) {\n return {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n };\n }\n\n if (settings.logger) {\n return settings.logger;\n }\n\n const isVerbose = settings.verbose ?? false;\n return {\n debug: (msg) => isVerbose && console.debug(msg),\n info: (msg) => isVerbose && console.info(msg),\n warn: (msg) => console.warn(msg),\n error: (msg) => console.error(msg),\n };\n}\n\n/**\n * Creates a SandAgent provider instance with the specified configuration.\n *\n * @example\n * ```typescript\n * import { createSandAgent } from '@sandagent/sdk';\n * import { E2BSandbox } from '@sandagent/sandbox-e2b';\n * import { generateText } from 'ai';\n *\n * const sandagent = createSandAgent({\n * sandbox: new E2BSandbox({ apiKey: process.env.E2B_API_KEY! }),\n * env: {\n * ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,\n * },\n * });\n *\n * const { text } = await generateText({\n * model: sandagent('sonnet'),\n * prompt: 'Create a hello world program',\n * });\n * ```\n */\nexport function createSandAgent(\n defaultOptions: SandAgentProviderSettings,\n): SandAgentProvider {\n const logger = getLogger(defaultOptions);\n\n if (!defaultOptions.sandbox) {\n throw new Error(\n \"SandAgent provider requires a sandbox adapter. \" +\n \"Please provide one, e.g.: new E2BSandbox({ apiKey: 'xxx' })\",\n );\n }\n\n const createModel = (\n modelId: SandAgentModelId,\n options: Partial<SandAgentProviderSettings> = {},\n ): LanguageModelV3 => {\n const runnerKind = getRunnerKindForModel(modelId);\n const resolvedModelId = resolveModelId(modelId);\n\n const runner: RunnerSpec = {\n kind: runnerKind,\n model: resolvedModelId,\n outputFormat: \"stream\",\n };\n\n const mergedOptions = {\n ...defaultOptions,\n ...options,\n runner,\n env: {\n ...defaultOptions.env,\n ...options.env,\n },\n artifactProcessors: [\n ...(defaultOptions.artifactProcessors ?? []),\n ...(options.artifactProcessors ?? []),\n ],\n } as SandAgentProviderSettings & { runner: RunnerSpec };\n\n logger.debug(\n `[sandagent] Creating model: ${modelId} with runner: ${runner.kind}`,\n );\n\n return new SandAgentLanguageModel({\n id: modelId,\n options: mergedOptions,\n });\n };\n\n const provider = function (\n modelId: SandAgentModelId,\n options?: Partial<SandAgentProviderSettings>,\n ) {\n if (new.target) {\n throw new Error(\n \"The SandAgent model function cannot be called with the new keyword.\",\n );\n }\n\n return createModel(modelId, options);\n };\n\n provider.languageModel = createModel;\n provider.chat = createModel;\n provider.specificationVersion = \"v3\" as const;\n\n provider.embeddingModel = (modelId: string): EmbeddingModelV3 => {\n throw new NoSuchModelError({\n modelId,\n modelType: \"embeddingModel\",\n });\n };\n\n provider.textEmbeddingModel = (modelId: string): EmbeddingModelV3 => {\n throw new NoSuchModelError({\n modelId,\n modelType: \"embeddingModel\",\n });\n };\n\n provider.imageModel = (modelId: string): ImageModelV3 => {\n throw new NoSuchModelError({\n modelId,\n modelType: \"imageModel\",\n });\n };\n\n return provider as SandAgentProvider;\n}\n","import type {\n JSONObject,\n JSONValue,\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Content,\n LanguageModelV3FinishReason,\n LanguageModelV3GenerateResult,\n LanguageModelV3Prompt,\n LanguageModelV3StreamPart,\n LanguageModelV3StreamResult,\n LanguageModelV3Usage,\n SharedV3ProviderMetadata,\n SharedV3Warning,\n} from \"@ai-sdk/provider\";\nimport { type Message, type RunnerSpec, SandAgent } from \"@sandagent/manager\";\nimport type {\n Logger,\n SandAgentModelId,\n SandAgentProviderSettings,\n} from \"./types\";\nimport { resolveModelId } from \"./types\";\n\n/**\n * Options for creating a SandAgent language model instance.\n */\nexport interface SandAgentLanguageModelOptions {\n id: SandAgentModelId;\n options: SandAgentProviderSettings & { runner: RunnerSpec };\n}\n\nfunction getLogger(settings: SandAgentProviderSettings): Logger {\n if (settings.logger === false) {\n return {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n };\n }\n\n if (settings.logger) {\n return settings.logger;\n }\n\n const isVerbose = settings.verbose ?? false;\n return {\n debug: (msg) => isVerbose && console.debug(msg),\n info: (msg) => isVerbose && console.info(msg),\n warn: (msg) => console.warn(msg),\n error: (msg) => console.error(msg),\n };\n}\n\nfunction createEmptyUsage(): LanguageModelV3Usage {\n return {\n inputTokens: {\n total: 0,\n noCache: 0,\n cacheRead: 0,\n cacheWrite: 0,\n },\n outputTokens: {\n total: 0,\n text: undefined,\n reasoning: undefined,\n },\n raw: undefined,\n };\n}\n\n/**\n * SandAgent Language Model implementation for AI SDK.\n */\nexport class SandAgentLanguageModel implements LanguageModelV3 {\n readonly specificationVersion = \"v3\" as const;\n readonly provider = \"sandagent\";\n readonly modelId: string;\n readonly supportedUrls: Record<string, RegExp[]> = {\n \"image/*\": [/.*/],\n };\n\n private readonly options: SandAgentProviderSettings & { runner: RunnerSpec };\n private readonly logger: Logger;\n private sessionId: string | undefined;\n private toolNameMap: Map<string, string> = new Map();\n\n constructor(modelOptions: SandAgentLanguageModelOptions) {\n this.modelId = resolveModelId(modelOptions.id);\n this.options = modelOptions.options;\n this.logger = getLogger(modelOptions.options);\n }\n\n async doGenerate(\n options: LanguageModelV3CallOptions,\n ): Promise<LanguageModelV3GenerateResult> {\n const { stream, request } = await this.doStream(options);\n const reader = stream.getReader();\n\n const content: LanguageModelV3Content[] = [];\n const warnings: SharedV3Warning[] = [];\n let finishReason: LanguageModelV3FinishReason = {\n unified: \"other\",\n raw: undefined,\n };\n let usage: LanguageModelV3Usage = createEmptyUsage();\n let providerMetadata: SharedV3ProviderMetadata | undefined;\n\n const textParts: Map<string, { text: string }> = new Map();\n const toolInputs: Map<string, { toolName: string; input: string }> =\n new Map();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n switch (value.type) {\n case \"text-start\": {\n textParts.set(value.id, { text: \"\" });\n break;\n }\n case \"text-delta\": {\n const part = textParts.get(value.id);\n if (part) {\n part.text += value.delta;\n }\n break;\n }\n case \"text-end\": {\n const part = textParts.get(value.id);\n if (part) {\n content.push({\n type: \"text\",\n text: part.text,\n });\n }\n break;\n }\n case \"tool-input-start\": {\n toolInputs.set(value.id, { toolName: value.toolName, input: \"\" });\n break;\n }\n case \"tool-input-delta\": {\n const tool = toolInputs.get(value.id);\n if (tool) {\n tool.input += value.delta;\n }\n break;\n }\n case \"tool-input-end\": {\n break;\n }\n case \"tool-call\": {\n content.push({\n type: \"tool-call\",\n toolCallId: value.toolCallId,\n toolName: value.toolName,\n input: value.input,\n providerExecuted: value.providerExecuted,\n });\n break;\n }\n case \"stream-start\": {\n warnings.push(...value.warnings);\n break;\n }\n case \"finish\": {\n finishReason = value.finishReason;\n usage = value.usage;\n providerMetadata = value.providerMetadata;\n break;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n return {\n content,\n finishReason,\n usage,\n providerMetadata,\n request,\n warnings,\n };\n }\n\n async doStream(\n options: LanguageModelV3CallOptions,\n ): Promise<LanguageModelV3StreamResult> {\n const { prompt, abortSignal } = options;\n const messages = this.convertPromptToMessages(prompt);\n\n this.logger.debug(\n `[sandagent] Starting stream with ${messages.length} messages`,\n );\n\n const sandbox = this.options.sandbox;\n const sandboxEnv = sandbox.getEnv?.() ?? {};\n const sandboxWorkdir =\n this.options.cwd ?? sandbox.getWorkdir?.() ?? \"/workspace\";\n\n const agent = new SandAgent({\n sandbox: this.options.sandbox,\n runner: this.options.runner,\n env: { ...sandboxEnv, ...this.options.env },\n });\n\n try {\n const stream = await agent.stream({\n messages,\n workspace: {\n path: sandboxWorkdir,\n },\n resume: this.options.resume,\n signal: abortSignal,\n });\n\n const self = this;\n const reader = stream.getReader();\n\n if (!reader) {\n throw new Error(\"Response body is not readable\");\n }\n\n const outputStream = new ReadableStream<LanguageModelV3StreamPart>({\n async start(controller) {\n try {\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n if (buffer.trim()) {\n const parts = self.parseSSEBuffer(buffer);\n for (const part of parts) {\n controller.enqueue(part);\n }\n }\n controller.close();\n break;\n }\n\n const text = new TextDecoder().decode(value);\n buffer += text;\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n let foundDone = false;\n for (const line of lines) {\n if (line.startsWith(\"data: \")) {\n const data = line.slice(6);\n\n if (data === \"[DONE]\") {\n foundDone = true;\n continue;\n }\n try {\n const parts = self.parseSSEData(data);\n for (const part of parts) {\n controller.enqueue(part);\n\n if (\n self.options.artifactProcessors?.length &&\n self.sessionId\n ) {\n const sessionId: string = self.sessionId;\n for (const processor of self.options\n .artifactProcessors) {\n Promise.resolve()\n .then(() => processor.onChange(part, sessionId))\n .catch((e) => {\n self.logger.error(\n `[sandagent] Artifact processor error: ${e}`,\n );\n });\n }\n }\n }\n } catch (e) {\n self.logger.error(\n `[sandagent] Failed to parse SSE data: ${e}`,\n );\n }\n }\n }\n\n if (foundDone) {\n controller.close();\n return;\n }\n }\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n self.logger.info(\"[sandagent] Stream aborted by user\");\n } else {\n self.logger.error(`[sandagent] Stream error: ${error}`);\n }\n controller.error(error);\n }\n },\n\n cancel() {\n reader.cancel();\n },\n });\n\n return {\n stream: outputStream,\n request: {\n body: JSON.stringify({ messages }),\n },\n };\n } catch (error) {\n await agent.destroy().catch(() => {});\n throw error;\n }\n }\n\n private parseSSEBuffer(buffer: string): LanguageModelV3StreamPart[] {\n const parts: LanguageModelV3StreamPart[] = [];\n const lines = buffer.split(\"\\n\");\n\n for (const line of lines) {\n if (line.startsWith(\"data: \")) {\n const data = line.slice(6);\n\n if (data === \"[DONE]\") {\n continue;\n }\n\n try {\n const parsedParts = this.parseSSEData(data);\n parts.push(...parsedParts);\n } catch (e) {\n this.logger.error(`[sandagent] Failed to parse SSE data: ${e}`);\n }\n }\n }\n\n return parts;\n }\n\n private parseSSEData(data: string): LanguageModelV3StreamPart[] {\n const parts: LanguageModelV3StreamPart[] = [];\n const parsed = JSON.parse(data) as Record<string, unknown>;\n\n switch (parsed.type) {\n case \"start\": {\n break;\n }\n\n case \"message-metadata\": {\n const metadata = parsed.messageMetadata as Record<string, unknown>;\n if (metadata?.sessionId && typeof metadata.sessionId === \"string\") {\n this.sessionId = metadata.sessionId;\n this.logger.debug(\n `[sandagent] Session ID extracted: ${this.sessionId}`,\n );\n parts.push({\n type: \"raw\",\n rawValue: this.sessionId,\n });\n }\n break;\n }\n\n case \"text-start\": {\n parts.push({\n type: \"text-start\",\n id: parsed.id as string,\n providerMetadata: {\n sandagent: {\n sessionId: this.sessionId,\n },\n },\n });\n break;\n }\n\n case \"text-delta\": {\n parts.push({\n type: \"text-delta\",\n id: parsed.id as string,\n delta: parsed.delta as string,\n });\n break;\n }\n\n case \"text-end\": {\n parts.push({\n type: \"text-end\",\n id: parsed.id as string,\n });\n break;\n }\n\n case \"tool-input-start\": {\n parts.push({\n type: \"tool-input-start\",\n id: parsed.toolCallId as string,\n toolName: parsed.toolName as string,\n dynamic: parsed.dynamic as boolean,\n providerExecuted: parsed.providerExecuted as boolean,\n });\n break;\n }\n\n case \"tool-input-delta\": {\n parts.push({\n type: \"tool-input-delta\",\n id: parsed.toolCallId as string,\n delta: parsed.inputTextDelta as string,\n });\n break;\n }\n case \"tool-input-available\": {\n const toolCallId = parsed.toolCallId as string;\n const toolName = parsed.toolName as string;\n const input = parsed.input as Record<string, unknown>;\n this.toolNameMap.set(toolCallId, toolName);\n parts.push({\n type: \"tool-call\",\n toolCallId,\n toolName,\n input: JSON.stringify(input),\n dynamic: parsed.dynamic as boolean,\n providerExecuted: parsed.providerExecuted as boolean,\n });\n break;\n }\n\n case \"tool-output-available\": {\n const toolName = this.toolNameMap.get(parsed.toolCallId as string);\n parts.push({\n type: \"tool-result\",\n toolCallId: parsed.toolCallId as string,\n toolName: toolName ?? \"\",\n result: parsed.output as NonNullable<JSONValue>,\n isError: parsed.isError as boolean,\n dynamic: parsed.dynamic as boolean,\n });\n break;\n }\n case \"error\": {\n parts.push({\n type: \"error\",\n error: new Error(parsed.errorText as string),\n });\n break;\n }\n\n case \"finish\": {\n const rawFinishReason = parsed.finishReason;\n let finishReason: LanguageModelV3FinishReason;\n\n if (\n typeof rawFinishReason === \"object\" &&\n rawFinishReason !== null &&\n \"unified\" in rawFinishReason\n ) {\n finishReason = rawFinishReason as LanguageModelV3FinishReason;\n } else {\n finishReason = this.mapFinishReason(rawFinishReason as string);\n }\n\n const { usage: rawUsage } = parsed.messageMetadata as {\n usage: Record<string, unknown>;\n };\n const usage = this.convertUsage(rawUsage);\n\n parts.push({\n type: \"finish\",\n finishReason,\n usage,\n providerMetadata: {\n sandagent: parsed.messageMetadata,\n } as SharedV3ProviderMetadata,\n });\n break;\n }\n }\n\n return parts;\n }\n\n private convertPromptToMessages(prompt: LanguageModelV3Prompt): Message[] {\n const messages: Message[] = [];\n\n for (const message of prompt) {\n switch (message.role) {\n case \"system\": {\n messages.push({\n role: \"system\",\n content: message.content,\n });\n break;\n }\n\n case \"user\": {\n const textParts = message.content\n .filter(\n (part): part is { type: \"text\"; text: string } =>\n part.type === \"text\",\n )\n .map((part) => part.text);\n\n if (textParts.length > 0) {\n messages.push({\n role: \"user\",\n content: textParts.join(\"\\n\"),\n });\n }\n break;\n }\n\n case \"assistant\": {\n const textParts = message.content\n .filter(\n (part): part is { type: \"text\"; text: string } =>\n part.type === \"text\",\n )\n .map((part) => part.text);\n\n if (textParts.length > 0) {\n messages.push({\n role: \"assistant\",\n content: textParts.join(\"\\n\"),\n });\n }\n break;\n }\n\n case \"tool\": {\n break;\n }\n }\n }\n\n return messages;\n }\n\n private mapFinishReason(\n reason: string | undefined,\n ): LanguageModelV3FinishReason {\n switch (reason) {\n case \"stop\":\n return { unified: \"stop\", raw: reason };\n case \"length\":\n return { unified: \"length\", raw: reason };\n case \"tool_calls\":\n case \"tool-calls\":\n return { unified: \"tool-calls\", raw: reason };\n case \"content_filter\":\n case \"content-filter\":\n return { unified: \"content-filter\", raw: reason };\n case \"error\":\n return { unified: \"error\", raw: reason };\n default:\n return { unified: \"other\", raw: reason ?? \"unknown\" };\n }\n }\n\n private convertUsage(\n data: Record<string, unknown> | undefined,\n ): LanguageModelV3Usage {\n if (!data) {\n return createEmptyUsage();\n }\n\n if (\"inputTokens\" in data && \"outputTokens\" in data) {\n const inputTokens = data.inputTokens as Record<string, number>;\n const outputTokens = data.outputTokens as Record<string, number>;\n // Check if there's a raw field in the data\n const rawData =\n \"raw\" in data ? (data.raw as Record<string, unknown>) : data;\n\n return {\n inputTokens: {\n total: inputTokens.total ?? 0,\n noCache: inputTokens.noCache ?? 0,\n cacheRead: inputTokens.cacheRead ?? 0,\n cacheWrite: inputTokens.cacheWrite ?? 0,\n },\n outputTokens: {\n total: outputTokens.total ?? 0,\n text: outputTokens.text ?? outputTokens.textTokens ?? undefined,\n reasoning:\n outputTokens.reasoning ?? outputTokens.reasoningTokens ?? undefined,\n },\n raw: rawData as JSONObject,\n };\n }\n\n const usage = (data.usage ?? data) as Record<string, number | undefined>;\n\n if (\"input_tokens\" in usage || \"output_tokens\" in usage) {\n const inputTokens = (usage.input_tokens as number) ?? 0;\n const outputTokens = (usage.output_tokens as number) ?? 0;\n const cacheWrite = (usage.cache_creation_input_tokens as number) ?? 0;\n const cacheRead = (usage.cache_read_input_tokens as number) ?? 0;\n // Check for text/reasoning tokens if available\n const textTokens = (usage.text_tokens as number) ?? undefined;\n const reasoningTokens = (usage.reasoning_tokens as number) ?? undefined;\n\n return {\n inputTokens: {\n total: inputTokens + cacheWrite + cacheRead,\n noCache: inputTokens,\n cacheRead,\n cacheWrite,\n },\n outputTokens: {\n total: outputTokens,\n text: textTokens,\n reasoning: reasoningTokens,\n },\n raw: usage as JSONObject,\n };\n }\n\n return createEmptyUsage();\n }\n}\n","import type { LanguageModelV3StreamPart } from \"@ai-sdk/provider\";\nimport type { SandAgentOptions } from \"@sandagent/manager\";\n\n/**\n * Artifact Processor 返回结果\n */\nexport interface ArtifactResult {\n artifactId: string;\n content: string;\n mimeType?: string;\n}\n\n/**\n * Stream writer interface for writing data parts\n */\nexport interface StreamWriter {\n write(chunk: {\n type: string;\n id?: string;\n data?: unknown;\n transient?: boolean;\n }): void;\n}\n\n/**\n * Artifact Processor 接口\n */\nexport interface ArtifactProcessor {\n /**\n * 当收到 stream part 时触发\n * @param event - Stream part 事件\n * @param sessionId - 当前会话 ID(taskId)\n */\n onChange(event: LanguageModelV3StreamPart, sessionId: string): Promise<void>;\n}\n\n/**\n * Logger interface for custom logging.\n */\nexport interface Logger {\n debug: (message: string) => void;\n info: (message: string) => void;\n warn: (message: string) => void;\n error: (message: string) => void;\n}\n\n/**\n * AI Provider specific settings that extend SandAgentOptions.\n */\nexport interface SandAgentProviderSettings\n extends Omit<SandAgentOptions, \"runner\" | \"sandboxId\"> {\n /** Working directory for CLI operations inside the sandbox. */\n cwd?: string;\n /** Resume session ID for multi-turn conversation. */\n resume?: string;\n /** Enable verbose logging for debugging. */\n verbose?: boolean;\n /** Custom logger for handling warnings and errors. */\n logger?: Logger | false;\n /** Artifact processors for handling artifact events. */\n artifactProcessors?: ArtifactProcessor[];\n}\n\n/**\n * Supported model identifiers for SandAgent.\n */\nexport type SandAgentModelId =\n | \"claude-sonnet-4-20250514\"\n | \"claude-opus-4-20250514\"\n | \"claude-sonnet-4.5-20250514\"\n | \"claude-opus-4.5-20250514\"\n | \"claude-4-5-sonnet-20250514\"\n | \"claude-4-5-opus-20250514\"\n | \"claude-3-7-sonnet-20250219\"\n | \"claude-3-5-sonnet-20241022\"\n | \"claude-3-5-haiku-20241022\"\n | \"claude-3-opus-20240229\"\n | \"claude-3-sonnet-20240229\"\n | \"claude-3-haiku-20240307\"\n | \"sonnet\"\n | \"opus\"\n | \"haiku\"\n | (string & {});\n\n/**\n * Maps model aliases to full model IDs\n */\nexport function resolveModelId(modelId: SandAgentModelId): string {\n switch (modelId) {\n case \"sonnet\":\n return \"claude-sonnet-4-20250514\";\n case \"opus\":\n return \"claude-opus-4-20250514\";\n case \"haiku\":\n return \"claude-3-5-haiku-20241022\";\n default:\n return modelId;\n }\n}\n\n/**\n * Determine the runner kind based on model ID\n */\nexport function getRunnerKindForModel(\n modelId: SandAgentModelId,\n): \"claude-agent-sdk\" {\n const resolvedId = resolveModelId(modelId);\n\n if (\n resolvedId.startsWith(\"claude\") ||\n resolvedId.includes(\"anthropic\") ||\n resolvedId.startsWith(\"us.anthropic\")\n ) {\n return \"claude-agent-sdk\";\n }\n\n return \"claude-agent-sdk\";\n}\n","/**\n * @sandagent/sdk\n *\n * SandAgent SDK - AI Provider and React hooks for building AI chat interfaces.\n *\n * Main entry point exports the AI provider (backend).\n * React hooks are available via \"@sandagent/sdk/react\".\n *\n * @example\n * ```typescript\n * // Backend - Provider\n * import { createSandAgent } from \"@sandagent/sdk\";\n * const sandagent = createSandAgent({ sandbox, env });\n * const model = sandagent(\"sonnet\");\n *\n * // Frontend - React hooks\n * import { useSandAgentChat } from \"@sandagent/sdk/react\";\n * const { messages, sendMessage } = useSandAgentChat({ apiEndpoint: \"/api/ai\" });\n * ```\n */\n\n// Provider exports\nexport {\n createSandAgent,\n SandAgentLanguageModel,\n resolveModelId,\n} from \"./provider\";\n\nexport type {\n SandAgentProvider,\n SandAgentProviderSettings,\n SandAgentLanguageModelOptions,\n SandAgentModelId,\n Logger,\n ArtifactProcessor,\n ArtifactResult,\n StreamWriter,\n // Re-exports from @sandagent/manager\n SandboxAdapter,\n SandboxHandle,\n TranscriptEntry,\n Message,\n // Re-exports from @ai-sdk/provider\n LanguageModelV3StreamPart,\n} from \"./provider\";\n\n// Re-export LocalSandbox for convenience\nexport { LocalSandbox } from \"@sandagent/manager\";\nexport type { LocalSandboxOptions } from \"@sandagent/manager\";\n\nexport const VERSION = \"0.1.0\";\n"],"mappings":"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","names":["getLogger"]}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -17,15 +17,11 @@ interface UseSandAgentChatOptions {
|
|
|
17
17
|
apiEndpoint?: string;
|
|
18
18
|
/** Additional body params to pass to API on each request */
|
|
19
19
|
body?: Record<string, unknown>;
|
|
20
|
-
/** Session ID (auto-generated if not provided) */
|
|
21
|
-
sessionId?: string;
|
|
22
20
|
}
|
|
23
21
|
/**
|
|
24
22
|
* Return type for useSandAgentChat hook
|
|
25
23
|
*/
|
|
26
24
|
interface UseSandAgentChatReturn {
|
|
27
|
-
/** Current session ID */
|
|
28
|
-
sessionId: string;
|
|
29
25
|
/** All chat messages */
|
|
30
26
|
messages: UIMessage[];
|
|
31
27
|
/** Current chat status */
|
|
@@ -223,7 +219,7 @@ interface UseArtifactsReturn$1 {
|
|
|
223
219
|
* });
|
|
224
220
|
* ```
|
|
225
221
|
*/
|
|
226
|
-
declare function useSandAgentChat({ apiEndpoint, body,
|
|
222
|
+
declare function useSandAgentChat({ apiEndpoint, body, }?: UseSandAgentChatOptions): UseSandAgentChatReturn;
|
|
227
223
|
|
|
228
224
|
/**
|
|
229
225
|
* useAskUserQuestion - Hook for handling AskUserQuestion tool interactions
|
package/dist/react/index.js
CHANGED
|
@@ -7,12 +7,8 @@ import { DefaultChatTransport } from "ai";
|
|
|
7
7
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
8
8
|
function useSandAgentChat({
|
|
9
9
|
apiEndpoint = "/api/ai",
|
|
10
|
-
body = {}
|
|
11
|
-
sessionId: providedSessionId
|
|
10
|
+
body = {}
|
|
12
11
|
} = {}) {
|
|
13
|
-
const [sessionId] = useState(
|
|
14
|
-
() => providedSessionId || `session-${Date.now()}`
|
|
15
|
-
);
|
|
16
12
|
const [selectedArtifact, setSelectedArtifact] = useState(
|
|
17
13
|
null
|
|
18
14
|
);
|
|
@@ -34,7 +30,6 @@ function useSandAgentChat({
|
|
|
34
30
|
const lastMessage = messagesRef.current[messagesRef.current.length - 1];
|
|
35
31
|
const metadata = lastMessage?.metadata;
|
|
36
32
|
return {
|
|
37
|
-
sessionId,
|
|
38
33
|
resume: metadata?.sessionId,
|
|
39
34
|
...bodyRef.current
|
|
40
35
|
};
|
|
@@ -115,7 +110,6 @@ function useSandAgentChat({
|
|
|
115
110
|
[isLoading, sendMessageInternal]
|
|
116
111
|
);
|
|
117
112
|
return {
|
|
118
|
-
sessionId,
|
|
119
113
|
messages,
|
|
120
114
|
status,
|
|
121
115
|
error,
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react/useSandAgentChat.ts","../../src/react/useAskUserQuestion.ts","../../src/react/useWriteTool.ts","../../src/react/useArtifacts.ts"],"sourcesContent":["\"use client\";\n\nimport { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport, type UIMessage } from \"ai\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type {\n ArtifactData,\n UseSandAgentChatOptions,\n UseSandAgentChatReturn,\n} from \"./types\";\n\n/**\n * useSandAgentChat - Core hook for SandAgent chat functionality\n *\n * Provides all the logic needed for a chat interface:\n * - Message management\n * - Artifact extraction\n * - Session management\n *\n * @example\n * ```tsx\n * import { useSandAgentChat } from \"@sandagent/sdk/react\";\n *\n * const {\n * messages,\n * sendMessage,\n * status,\n * artifacts,\n * selectedArtifact,\n * setSelectedArtifact,\n * } = useSandAgentChat({\n * apiEndpoint: \"/api/ai\",\n * body: { template: \"default\" },\n * });\n * ```\n */\nexport function useSandAgentChat({\n apiEndpoint = \"/api/ai\",\n body = {},\n sessionId: providedSessionId,\n}: UseSandAgentChatOptions = {}): UseSandAgentChatReturn {\n // Session ID management\n const [sessionId] = useState(\n () => providedSessionId || `session-${Date.now()}`,\n );\n\n // Artifact selection state\n const [selectedArtifact, setSelectedArtifact] = useState<ArtifactData | null>(\n null,\n );\n\n // Refs for accessing latest values in callbacks\n const bodyRef = useRef(body);\n const messagesRef = useRef<UIMessage[]>([]);\n\n useEffect(() => {\n bodyRef.current = body;\n }, [body]);\n\n // Core chat hook\n const {\n messages,\n sendMessage: sendMessageInternal,\n status,\n error,\n stop,\n } = useChat({\n transport: new DefaultChatTransport({\n api: apiEndpoint,\n body: () => {\n const lastMessage = messagesRef.current[messagesRef.current.length - 1];\n const metadata = lastMessage?.metadata as\n | { sessionId?: string }\n | undefined;\n return {\n sessionId,\n resume: metadata?.sessionId,\n ...bodyRef.current,\n };\n },\n }),\n });\n\n // Keep messagesRef in sync\n useEffect(() => {\n messagesRef.current = messages;\n }, [messages]);\n\n // Extract artifacts from messages\n const prevArtifactsRef = useRef<ArtifactData[]>([]);\n const artifacts = useMemo(() => {\n const results: ArtifactData[] = [];\n for (const message of messages) {\n for (const part of message.parts) {\n if (part.type === \"data-artifact\") {\n const data = part.data as ArtifactData;\n if (!results.some((a) => a.artifactId === data.artifactId)) {\n results.push(data);\n }\n }\n }\n }\n\n // Memoization optimization\n const prev = prevArtifactsRef.current;\n if (\n prev.length === results.length &&\n prev.every((prevArt, idx) => {\n const currArt = results[idx];\n return (\n prevArt.artifactId === currArt.artifactId &&\n prevArt.content === currArt.content &&\n prevArt.mimeType === currArt.mimeType\n );\n })\n ) {\n return prev;\n }\n\n prevArtifactsRef.current = results;\n return results;\n }, [messages]);\n\n // Sync selectedArtifact when artifacts change\n useEffect(() => {\n if (artifacts.length > 0) {\n setSelectedArtifact((prev) => {\n if (!prev) return artifacts[0];\n\n const currentMatch = artifacts.find(\n (a) => a.artifactId === prev.artifactId,\n );\n\n if (!currentMatch) {\n return artifacts[0];\n }\n\n if (\n currentMatch.content === prev.content &&\n currentMatch.mimeType === prev.mimeType\n ) {\n return prev;\n }\n\n return currentMatch;\n });\n } else {\n setSelectedArtifact((prev) => (prev === null ? prev : null));\n }\n }, [artifacts]);\n\n const isLoading = status === \"streaming\" || status === \"submitted\";\n const hasError = status === \"error\" && !!error;\n\n // Send message helper\n const sendMessage = useCallback(\n (text: string) => {\n if (!isLoading && text.trim()) {\n sendMessageInternal({\n role: \"user\",\n parts: [{ type: \"text\", text: text.trim() }],\n });\n }\n },\n [isLoading, sendMessageInternal],\n );\n\n // Handle submit for PromptInput compatibility\n const handleSubmit = useCallback(\n (message: { text: string }) => {\n if (!isLoading) {\n if (message.text) {\n sendMessageInternal({\n role: \"user\",\n parts: [{ type: \"text\", text: message.text.trim() }],\n });\n } else {\n sendMessageInternal();\n }\n }\n },\n [isLoading, sendMessageInternal],\n );\n\n return {\n sessionId,\n messages,\n status,\n error,\n isLoading,\n hasError,\n artifacts,\n selectedArtifact,\n setSelectedArtifact,\n sendMessage,\n stop,\n handleSubmit,\n };\n}\n","\"use client\";\n\nimport { useCallback, useMemo, useState } from \"react\";\nimport type {\n AskUserQuestionInput,\n AskUserQuestionOutput,\n Question,\n UseAskUserQuestionOptions,\n UseAskUserQuestionReturn,\n} from \"./types\";\n\n/**\n * useAskUserQuestion - Hook for handling AskUserQuestion tool interactions\n *\n * Manages the state for user question/answer interactions in chat.\n * Provides answer selection, completion detection, and formatted output.\n *\n * @example\n * ```tsx\n * import { useAskUserQuestion } from \"@sandagent/sdk/react\";\n *\n * function QuestionUI({ part, sessionId }) {\n * const {\n * questions,\n * answers,\n * isCompleted,\n * selectAnswer,\n * isSelected,\n * } = useAskUserQuestion({\n * part,\n * onAnswer: (data) => {\n * fetch(\"/api/approval/submit\", {\n * method: \"POST\",\n * body: JSON.stringify({ sessionId, ...data }),\n * });\n * },\n * });\n *\n * if (isCompleted) {\n * return <div>Completed</div>;\n * }\n *\n * return (\n * <div>\n * {questions.map((q) => (\n * <div key={q.question}>\n * <p>{q.question}</p>\n * {q.options?.map((opt) => (\n * <button\n * key={opt.label}\n * onClick={() => selectAnswer(q.question, opt.label, q.multiSelect)}\n * style={{ fontWeight: isSelected(q.question, opt.label, q.multiSelect) ? 'bold' : 'normal' }}\n * >\n * {opt.label}\n * </button>\n * ))}\n * </div>\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport function useAskUserQuestion({\n part,\n onAnswer,\n}: UseAskUserQuestionOptions): UseAskUserQuestionReturn {\n const [answers, setAnswers] = useState<Record<string, string | string[]>>({});\n\n // Parse questions from part.input\n const questions = useMemo((): Question[] => {\n if (!part.input || typeof part.input !== \"object\") return [];\n const input = part.input as AskUserQuestionInput;\n if (!input.questions || !Array.isArray(input.questions)) return [];\n return input.questions;\n }, [part.input]);\n\n // Parse answers from part.output (for restored sessions)\n const outputAnswers = useMemo((): Record<\n string,\n string | string[]\n > | null => {\n if (part.output && typeof part.output === \"object\") {\n const output = part.output as AskUserQuestionOutput;\n if (output.answers) {\n const hasRealAnswers = Object.values(output.answers).some(\n (v) => v && v.trim() !== \"\",\n );\n if (hasRealAnswers) {\n const parsed: Record<string, string | string[]> = {};\n for (const q of questions) {\n const val = output.answers[q.question];\n if (q.multiSelect && val) {\n parsed[q.question] = val.split(\", \").filter(Boolean);\n } else {\n parsed[q.question] = val || \"\";\n }\n }\n return parsed;\n }\n }\n }\n return null;\n }, [part.output, questions]);\n\n // Determine display answers (user input or restored from output)\n const displayAnswers = useMemo(() => {\n return Object.keys(answers).length > 0 ? answers : outputAnswers || {};\n }, [answers, outputAnswers]);\n\n // Check if completed\n const isCompleted = useMemo(() => {\n return (\n part.state === \"output-available\" ||\n (Object.keys(answers).length === 0 && outputAnswers !== null)\n );\n }, [part.state, answers, outputAnswers]);\n\n // Check if waiting for input (for animation)\n const isWaitingForInput = part.state === \"input-available\";\n\n // Get formatted answers map\n const getAnswersMap = useCallback((): Record<string, string> => {\n const answersMap: Record<string, string> = {};\n for (const q of questions) {\n const answer = displayAnswers[q.question];\n if (q.multiSelect) {\n answersMap[q.question] = Array.isArray(answer) ? answer.join(\", \") : \"\";\n } else {\n answersMap[q.question] = (answer as string) || \"\";\n }\n }\n return answersMap;\n }, [questions, displayAnswers]);\n\n // Select answer handler\n const selectAnswer = useCallback(\n (question: string, value: string, multiSelect = false) => {\n const newAnswers = { ...answers };\n\n if (multiSelect) {\n const current = (newAnswers[question] as string[]) || [];\n newAnswers[question] = current.includes(value)\n ? current.filter((v) => v !== value)\n : [...current, value];\n } else {\n newAnswers[question] = value;\n }\n\n setAnswers(newAnswers);\n\n // Prepare answers map for callback\n const answersMap: Record<string, string> = {};\n for (const q of questions) {\n const answer = newAnswers[q.question];\n if (q.multiSelect) {\n answersMap[q.question] = Array.isArray(answer)\n ? answer.join(\", \")\n : \"\";\n } else {\n answersMap[q.question] = (answer as string) || \"\";\n }\n }\n\n // Trigger callback\n onAnswer?.({\n toolCallId: part.toolCallId,\n questions,\n answers: answersMap,\n });\n },\n [answers, questions, part.toolCallId, onAnswer],\n );\n\n // Check if option is selected\n const isSelected = useCallback(\n (question: string, optionLabel: string, multiSelect = false): boolean => {\n const selectedValue = displayAnswers[question];\n if (multiSelect) {\n return (\n (selectedValue as string[] | undefined)?.includes(optionLabel) ??\n false\n );\n }\n return selectedValue === optionLabel;\n },\n [displayAnswers],\n );\n\n return {\n questions,\n answers: displayAnswers,\n isCompleted,\n isWaitingForInput,\n selectAnswer,\n getAnswersMap,\n isSelected,\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport type { DynamicToolUIPart } from \"./types\";\n\n/**\n * Write tool input structure\n */\nexport interface WriteToolInput {\n file_path: string;\n content: string;\n}\n\n/**\n * Write tool output structure\n */\nexport interface WriteToolOutput {\n type: \"create\" | \"edit\";\n filePath: string;\n content: string;\n structuredPatch?: unknown[];\n originalFile?: string | null;\n}\n\n/**\n * Options for useWriteTool hook\n */\nexport interface UseWriteToolOptions {\n /** The dynamic tool UI part from the message */\n part: DynamicToolUIPart;\n}\n\n/**\n * Return type for useWriteTool hook\n */\nexport interface UseWriteToolReturn {\n /** File path being written to */\n filePath: string | null;\n /** File name (extracted from path) */\n fileName: string | null;\n /** File content */\n content: string | null;\n /** Operation type: 'create' or 'edit' */\n operationType: \"create\" | \"edit\" | null;\n /** Original file content (for edit operations) */\n originalContent: string | null;\n /** Structured patch data (for edit operations) */\n structuredPatch: unknown[] | null;\n /** Tool state */\n state: \"streaming\" | \"input-available\" | \"output-available\" | \"error\";\n /** Whether the tool is currently streaming input */\n isStreaming: boolean;\n /** Whether the write operation completed successfully */\n isCompleted: boolean;\n /** Whether there was an error */\n hasError: boolean;\n /** Error message if any */\n errorText: string | null;\n /** Whether this is a markdown file */\n isMarkdown: boolean;\n /** File extension */\n fileExtension: string | null;\n}\n\n/**\n * useWriteTool - Hook for handling Write tool interactions\n *\n * Parses the Write tool's input and output data, providing\n * easy access to file information and operation state.\n *\n * @example\n * ```tsx\n * import { useWriteTool } from \"@sandagent/sdk/react\";\n *\n * function WriteToolUI({ part }) {\n * const {\n * filePath,\n * fileName,\n * content,\n * operationType,\n * isStreaming,\n * isCompleted,\n * isMarkdown,\n * } = useWriteTool({ part });\n *\n * if (isStreaming) {\n * return <div>Writing {fileName}...</div>;\n * }\n *\n * return (\n * <div>\n * <h3>{fileName} ({operationType})</h3>\n * {isMarkdown ? (\n * <MarkdownRenderer content={content} />\n * ) : (\n * <pre>{content}</pre>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useWriteTool({\n part,\n}: UseWriteToolOptions): UseWriteToolReturn {\n // Parse input data\n const inputData = useMemo((): WriteToolInput | null => {\n if (!part.input || typeof part.input !== \"object\") return null;\n const input = part.input as WriteToolInput;\n if (!input.file_path) return null;\n return input;\n }, [part.input]);\n\n // Parse output data\n const outputData = useMemo((): WriteToolOutput | null => {\n if (!part.output || typeof part.output !== \"object\") return null;\n const output = part.output as WriteToolOutput;\n if (!output.filePath) return null;\n return output;\n }, [part.output]);\n\n // Determine file path (prefer output, fallback to input)\n const filePath = outputData?.filePath ?? inputData?.file_path ?? null;\n\n // Extract file name\n const fileName = useMemo(() => {\n if (!filePath) return null;\n return filePath.split(\"/\").pop() || filePath;\n }, [filePath]);\n\n // Extract file extension\n const fileExtension = useMemo(() => {\n if (!fileName) return null;\n const parts = fileName.split(\".\");\n return parts.length > 1 ? parts.pop()?.toLowerCase() || null : null;\n }, [fileName]);\n\n // Determine content (prefer output, fallback to input)\n const content = outputData?.content ?? inputData?.content ?? null;\n\n // Operation type\n const operationType = outputData?.type ?? null;\n\n // Original content (for edits)\n const originalContent = outputData?.originalFile ?? null;\n\n // Structured patch\n const structuredPatch = outputData?.structuredPatch ?? null;\n\n // State parsing\n const state = useMemo((): UseWriteToolReturn[\"state\"] => {\n if (part.state === \"input-streaming\") return \"streaming\";\n if (part.state === \"output-error\") return \"error\";\n if (part.state === \"output-available\") return \"output-available\";\n return \"input-available\";\n }, [part.state]);\n\n const isStreaming = state === \"streaming\";\n const isCompleted = state === \"output-available\";\n const hasError = state === \"error\";\n const errorText = part.errorText ?? null;\n\n // Check if markdown\n const isMarkdown = useMemo(() => {\n if (!fileExtension) return false;\n return [\"md\", \"markdown\", \"mdx\"].includes(fileExtension);\n }, [fileExtension]);\n\n return {\n filePath,\n fileName,\n content,\n operationType,\n originalContent,\n structuredPatch,\n state,\n isStreaming,\n isCompleted,\n hasError,\n errorText,\n isMarkdown,\n fileExtension,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ArtifactData, UIMessage } from \"./types\";\n\n/**\n * Options for useArtifacts hook\n */\nexport interface UseArtifactsOptions {\n /** Messages to extract artifacts from */\n messages: UIMessage[];\n}\n\n/**\n * Return type for useArtifacts hook\n */\nexport interface UseArtifactsReturn {\n /** All extracted artifacts */\n artifacts: ArtifactData[];\n /** Currently selected artifact */\n selectedArtifact: ArtifactData | null;\n /** Set the selected artifact */\n setSelectedArtifact: (artifact: ArtifactData | null) => void;\n /** Select artifact by ID */\n selectArtifactById: (artifactId: string) => void;\n /** Whether there are any artifacts */\n hasArtifacts: boolean;\n /** Number of artifacts */\n count: number;\n /** Copy artifact content to clipboard */\n copyContent: (artifact: ArtifactData) => Promise<void>;\n /** Download artifact as file */\n downloadArtifact: (artifact: ArtifactData) => void;\n /** Get file extension from mime type */\n getFileExtension: (mimeType: string) => string;\n}\n\n/**\n * Get file extension from MIME type\n */\nfunction getFileExtensionFromMimeType(mimeType: string): string {\n const mimeToExtension: Record<string, string> = {\n \"text/plain\": \"txt\",\n \"text/html\": \"html\",\n \"text/css\": \"css\",\n \"text/javascript\": \"js\",\n \"text/markdown\": \"md\",\n \"application/json\": \"json\",\n \"application/xml\": \"xml\",\n \"application/pdf\": \"pdf\",\n \"image/png\": \"png\",\n \"image/jpeg\": \"jpg\",\n \"image/gif\": \"gif\",\n \"image/svg+xml\": \"svg\",\n };\n\n // Try exact match\n if (mimeToExtension[mimeType]) {\n return mimeToExtension[mimeType];\n }\n\n // Try partial match (e.g., \"text/x-markdown\" -> \"md\")\n if (mimeType.includes(\"markdown\")) return \"md\";\n if (mimeType.includes(\"json\")) return \"json\";\n if (mimeType.includes(\"javascript\")) return \"js\";\n if (mimeType.includes(\"typescript\")) return \"ts\";\n if (mimeType.includes(\"html\")) return \"html\";\n if (mimeType.includes(\"css\")) return \"css\";\n if (mimeType.includes(\"xml\")) return \"xml\";\n if (mimeType.includes(\"python\")) return \"py\";\n\n // Default\n return \"txt\";\n}\n\n/**\n * useArtifacts - Hook for managing artifacts from chat messages\n *\n * Extracts artifacts from messages and provides selection,\n * copy, and download functionality.\n *\n * @example\n * ```tsx\n * import { useArtifacts } from \"@sandagent/sdk/react\";\n *\n * function ArtifactPanel({ messages }) {\n * const {\n * artifacts,\n * selectedArtifact,\n * setSelectedArtifact,\n * hasArtifacts,\n * copyContent,\n * downloadArtifact,\n * } = useArtifacts({ messages });\n *\n * if (!hasArtifacts) return null;\n *\n * return (\n * <div>\n * {artifacts.map((artifact) => (\n * <button\n * key={artifact.artifactId}\n * onClick={() => setSelectedArtifact(artifact)}\n * >\n * {artifact.artifactId}\n * </button>\n * ))}\n *\n * {selectedArtifact && (\n * <div>\n * <pre>{selectedArtifact.content}</pre>\n * <button onClick={() => copyContent(selectedArtifact)}>Copy</button>\n * <button onClick={() => downloadArtifact(selectedArtifact)}>Download</button>\n * </div>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useArtifacts({\n messages,\n}: UseArtifactsOptions): UseArtifactsReturn {\n const [selectedArtifact, setSelectedArtifact] = useState<ArtifactData | null>(\n null,\n );\n\n // Extract artifacts from messages with memoization optimization\n const prevArtifactsRef = useRef<ArtifactData[]>([]);\n const artifacts = useMemo(() => {\n const results: ArtifactData[] = [];\n for (const message of messages) {\n for (const part of message.parts) {\n if (part.type === \"data-artifact\") {\n const data = part.data as ArtifactData;\n if (!results.some((a) => a.artifactId === data.artifactId)) {\n results.push(data);\n }\n }\n }\n }\n\n // Memoization optimization - return previous reference if content unchanged\n const prev = prevArtifactsRef.current;\n if (\n prev.length === results.length &&\n prev.every((prevArt, idx) => {\n const currArt = results[idx];\n return (\n prevArt.artifactId === currArt.artifactId &&\n prevArt.content === currArt.content &&\n prevArt.mimeType === currArt.mimeType\n );\n })\n ) {\n return prev;\n }\n\n prevArtifactsRef.current = results;\n return results;\n }, [messages]);\n\n // Sync selectedArtifact when artifacts change\n useEffect(() => {\n if (artifacts.length > 0) {\n setSelectedArtifact((prev) => {\n if (!prev) return artifacts[0];\n\n const currentMatch = artifacts.find(\n (a) => a.artifactId === prev.artifactId,\n );\n\n if (!currentMatch) {\n return artifacts[0];\n }\n\n if (\n currentMatch.content === prev.content &&\n currentMatch.mimeType === prev.mimeType\n ) {\n return prev;\n }\n\n return currentMatch;\n });\n } else {\n setSelectedArtifact((prev) => (prev === null ? prev : null));\n }\n }, [artifacts]);\n\n // Select artifact by ID\n const selectArtifactById = useCallback(\n (artifactId: string) => {\n const artifact = artifacts.find((a) => a.artifactId === artifactId);\n if (artifact) {\n setSelectedArtifact(artifact);\n }\n },\n [artifacts],\n );\n\n // Copy content to clipboard\n const copyContent = useCallback(async (artifact: ArtifactData) => {\n await navigator.clipboard.writeText(artifact.content);\n }, []);\n\n // Download artifact as file\n const downloadArtifact = useCallback((artifact: ArtifactData) => {\n const blob = new Blob([artifact.content], { type: artifact.mimeType });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n const fileName =\n artifact.artifactId.split(\"/\").pop() || artifact.artifactId;\n const extension = getFileExtensionFromMimeType(artifact.mimeType);\n a.download = fileName.includes(\".\") ? fileName : `${fileName}.${extension}`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n }, []);\n\n const hasArtifacts = artifacts.length > 0;\n const count = artifacts.length;\n\n return {\n artifacts,\n selectedArtifact,\n setSelectedArtifact,\n selectArtifactById,\n hasArtifacts,\n count,\n copyContent,\n downloadArtifact,\n getFileExtension: getFileExtensionFromMimeType,\n };\n}\n"],"mappings":"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","names":["useCallback","useMemo","useState","useMemo","useCallback","useEffect","useMemo","useRef","useState"]}
|
|
1
|
+
{"version":3,"sources":["../../src/react/useSandAgentChat.ts","../../src/react/useAskUserQuestion.ts","../../src/react/useWriteTool.ts","../../src/react/useArtifacts.ts"],"sourcesContent":["\"use client\";\n\nimport { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport, type UIMessage } from \"ai\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type {\n ArtifactData,\n UseSandAgentChatOptions,\n UseSandAgentChatReturn,\n} from \"./types\";\n\n/**\n * useSandAgentChat - Core hook for SandAgent chat functionality\n *\n * Provides all the logic needed for a chat interface:\n * - Message management\n * - Artifact extraction\n * - Session management\n *\n * @example\n * ```tsx\n * import { useSandAgentChat } from \"@sandagent/sdk/react\";\n *\n * const {\n * messages,\n * sendMessage,\n * status,\n * artifacts,\n * selectedArtifact,\n * setSelectedArtifact,\n * } = useSandAgentChat({\n * apiEndpoint: \"/api/ai\",\n * body: { template: \"default\" },\n * });\n * ```\n */\nexport function useSandAgentChat({\n apiEndpoint = \"/api/ai\",\n body = {},\n}: UseSandAgentChatOptions = {}): UseSandAgentChatReturn {\n // Artifact selection state\n const [selectedArtifact, setSelectedArtifact] = useState<ArtifactData | null>(\n null,\n );\n\n // Refs for accessing latest values in callbacks\n const bodyRef = useRef(body);\n const messagesRef = useRef<UIMessage[]>([]);\n\n useEffect(() => {\n bodyRef.current = body;\n }, [body]);\n\n // Core chat hook\n const {\n messages,\n sendMessage: sendMessageInternal,\n status,\n error,\n stop,\n } = useChat({\n transport: new DefaultChatTransport({\n api: apiEndpoint,\n body: () => {\n const lastMessage = messagesRef.current[messagesRef.current.length - 1];\n const metadata = lastMessage?.metadata as\n | { sessionId?: string }\n | undefined;\n return {\n resume: metadata?.sessionId,\n ...bodyRef.current,\n };\n },\n }),\n });\n\n // Keep messagesRef in sync\n useEffect(() => {\n messagesRef.current = messages;\n }, [messages]);\n\n // Extract artifacts from messages\n const prevArtifactsRef = useRef<ArtifactData[]>([]);\n const artifacts = useMemo(() => {\n const results: ArtifactData[] = [];\n for (const message of messages) {\n for (const part of message.parts) {\n if (part.type === \"data-artifact\") {\n const data = part.data as ArtifactData;\n if (!results.some((a) => a.artifactId === data.artifactId)) {\n results.push(data);\n }\n }\n }\n }\n\n // Memoization optimization\n const prev = prevArtifactsRef.current;\n if (\n prev.length === results.length &&\n prev.every((prevArt, idx) => {\n const currArt = results[idx];\n return (\n prevArt.artifactId === currArt.artifactId &&\n prevArt.content === currArt.content &&\n prevArt.mimeType === currArt.mimeType\n );\n })\n ) {\n return prev;\n }\n\n prevArtifactsRef.current = results;\n return results;\n }, [messages]);\n\n // Sync selectedArtifact when artifacts change\n useEffect(() => {\n if (artifacts.length > 0) {\n setSelectedArtifact((prev) => {\n if (!prev) return artifacts[0];\n\n const currentMatch = artifacts.find(\n (a) => a.artifactId === prev.artifactId,\n );\n\n if (!currentMatch) {\n return artifacts[0];\n }\n\n if (\n currentMatch.content === prev.content &&\n currentMatch.mimeType === prev.mimeType\n ) {\n return prev;\n }\n\n return currentMatch;\n });\n } else {\n setSelectedArtifact((prev) => (prev === null ? prev : null));\n }\n }, [artifacts]);\n\n const isLoading = status === \"streaming\" || status === \"submitted\";\n const hasError = status === \"error\" && !!error;\n\n // Send message helper\n const sendMessage = useCallback(\n (text: string) => {\n if (!isLoading && text.trim()) {\n sendMessageInternal({\n role: \"user\",\n parts: [{ type: \"text\", text: text.trim() }],\n });\n }\n },\n [isLoading, sendMessageInternal],\n );\n\n // Handle submit for PromptInput compatibility\n const handleSubmit = useCallback(\n (message: { text: string }) => {\n if (!isLoading) {\n if (message.text) {\n sendMessageInternal({\n role: \"user\",\n parts: [{ type: \"text\", text: message.text.trim() }],\n });\n } else {\n sendMessageInternal();\n }\n }\n },\n [isLoading, sendMessageInternal],\n );\n\n return {\n messages,\n status,\n error,\n isLoading,\n hasError,\n artifacts,\n selectedArtifact,\n setSelectedArtifact,\n sendMessage,\n stop,\n handleSubmit,\n };\n}\n","\"use client\";\n\nimport { useCallback, useMemo, useState } from \"react\";\nimport type {\n AskUserQuestionInput,\n AskUserQuestionOutput,\n Question,\n UseAskUserQuestionOptions,\n UseAskUserQuestionReturn,\n} from \"./types\";\n\n/**\n * useAskUserQuestion - Hook for handling AskUserQuestion tool interactions\n *\n * Manages the state for user question/answer interactions in chat.\n * Provides answer selection, completion detection, and formatted output.\n *\n * @example\n * ```tsx\n * import { useAskUserQuestion } from \"@sandagent/sdk/react\";\n *\n * function QuestionUI({ part, sessionId }) {\n * const {\n * questions,\n * answers,\n * isCompleted,\n * selectAnswer,\n * isSelected,\n * } = useAskUserQuestion({\n * part,\n * onAnswer: (data) => {\n * fetch(\"/api/approval/submit\", {\n * method: \"POST\",\n * body: JSON.stringify({ sessionId, ...data }),\n * });\n * },\n * });\n *\n * if (isCompleted) {\n * return <div>Completed</div>;\n * }\n *\n * return (\n * <div>\n * {questions.map((q) => (\n * <div key={q.question}>\n * <p>{q.question}</p>\n * {q.options?.map((opt) => (\n * <button\n * key={opt.label}\n * onClick={() => selectAnswer(q.question, opt.label, q.multiSelect)}\n * style={{ fontWeight: isSelected(q.question, opt.label, q.multiSelect) ? 'bold' : 'normal' }}\n * >\n * {opt.label}\n * </button>\n * ))}\n * </div>\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport function useAskUserQuestion({\n part,\n onAnswer,\n}: UseAskUserQuestionOptions): UseAskUserQuestionReturn {\n const [answers, setAnswers] = useState<Record<string, string | string[]>>({});\n\n // Parse questions from part.input\n const questions = useMemo((): Question[] => {\n if (!part.input || typeof part.input !== \"object\") return [];\n const input = part.input as AskUserQuestionInput;\n if (!input.questions || !Array.isArray(input.questions)) return [];\n return input.questions;\n }, [part.input]);\n\n // Parse answers from part.output (for restored sessions)\n const outputAnswers = useMemo((): Record<\n string,\n string | string[]\n > | null => {\n if (part.output && typeof part.output === \"object\") {\n const output = part.output as AskUserQuestionOutput;\n if (output.answers) {\n const hasRealAnswers = Object.values(output.answers).some(\n (v) => v && v.trim() !== \"\",\n );\n if (hasRealAnswers) {\n const parsed: Record<string, string | string[]> = {};\n for (const q of questions) {\n const val = output.answers[q.question];\n if (q.multiSelect && val) {\n parsed[q.question] = val.split(\", \").filter(Boolean);\n } else {\n parsed[q.question] = val || \"\";\n }\n }\n return parsed;\n }\n }\n }\n return null;\n }, [part.output, questions]);\n\n // Determine display answers (user input or restored from output)\n const displayAnswers = useMemo(() => {\n return Object.keys(answers).length > 0 ? answers : outputAnswers || {};\n }, [answers, outputAnswers]);\n\n // Check if completed\n const isCompleted = useMemo(() => {\n return (\n part.state === \"output-available\" ||\n (Object.keys(answers).length === 0 && outputAnswers !== null)\n );\n }, [part.state, answers, outputAnswers]);\n\n // Check if waiting for input (for animation)\n const isWaitingForInput = part.state === \"input-available\";\n\n // Get formatted answers map\n const getAnswersMap = useCallback((): Record<string, string> => {\n const answersMap: Record<string, string> = {};\n for (const q of questions) {\n const answer = displayAnswers[q.question];\n if (q.multiSelect) {\n answersMap[q.question] = Array.isArray(answer) ? answer.join(\", \") : \"\";\n } else {\n answersMap[q.question] = (answer as string) || \"\";\n }\n }\n return answersMap;\n }, [questions, displayAnswers]);\n\n // Select answer handler\n const selectAnswer = useCallback(\n (question: string, value: string, multiSelect = false) => {\n const newAnswers = { ...answers };\n\n if (multiSelect) {\n const current = (newAnswers[question] as string[]) || [];\n newAnswers[question] = current.includes(value)\n ? current.filter((v) => v !== value)\n : [...current, value];\n } else {\n newAnswers[question] = value;\n }\n\n setAnswers(newAnswers);\n\n // Prepare answers map for callback\n const answersMap: Record<string, string> = {};\n for (const q of questions) {\n const answer = newAnswers[q.question];\n if (q.multiSelect) {\n answersMap[q.question] = Array.isArray(answer)\n ? answer.join(\", \")\n : \"\";\n } else {\n answersMap[q.question] = (answer as string) || \"\";\n }\n }\n\n // Trigger callback\n onAnswer?.({\n toolCallId: part.toolCallId,\n questions,\n answers: answersMap,\n });\n },\n [answers, questions, part.toolCallId, onAnswer],\n );\n\n // Check if option is selected\n const isSelected = useCallback(\n (question: string, optionLabel: string, multiSelect = false): boolean => {\n const selectedValue = displayAnswers[question];\n if (multiSelect) {\n return (\n (selectedValue as string[] | undefined)?.includes(optionLabel) ??\n false\n );\n }\n return selectedValue === optionLabel;\n },\n [displayAnswers],\n );\n\n return {\n questions,\n answers: displayAnswers,\n isCompleted,\n isWaitingForInput,\n selectAnswer,\n getAnswersMap,\n isSelected,\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport type { DynamicToolUIPart } from \"./types\";\n\n/**\n * Write tool input structure\n */\nexport interface WriteToolInput {\n file_path: string;\n content: string;\n}\n\n/**\n * Write tool output structure\n */\nexport interface WriteToolOutput {\n type: \"create\" | \"edit\";\n filePath: string;\n content: string;\n structuredPatch?: unknown[];\n originalFile?: string | null;\n}\n\n/**\n * Options for useWriteTool hook\n */\nexport interface UseWriteToolOptions {\n /** The dynamic tool UI part from the message */\n part: DynamicToolUIPart;\n}\n\n/**\n * Return type for useWriteTool hook\n */\nexport interface UseWriteToolReturn {\n /** File path being written to */\n filePath: string | null;\n /** File name (extracted from path) */\n fileName: string | null;\n /** File content */\n content: string | null;\n /** Operation type: 'create' or 'edit' */\n operationType: \"create\" | \"edit\" | null;\n /** Original file content (for edit operations) */\n originalContent: string | null;\n /** Structured patch data (for edit operations) */\n structuredPatch: unknown[] | null;\n /** Tool state */\n state: \"streaming\" | \"input-available\" | \"output-available\" | \"error\";\n /** Whether the tool is currently streaming input */\n isStreaming: boolean;\n /** Whether the write operation completed successfully */\n isCompleted: boolean;\n /** Whether there was an error */\n hasError: boolean;\n /** Error message if any */\n errorText: string | null;\n /** Whether this is a markdown file */\n isMarkdown: boolean;\n /** File extension */\n fileExtension: string | null;\n}\n\n/**\n * useWriteTool - Hook for handling Write tool interactions\n *\n * Parses the Write tool's input and output data, providing\n * easy access to file information and operation state.\n *\n * @example\n * ```tsx\n * import { useWriteTool } from \"@sandagent/sdk/react\";\n *\n * function WriteToolUI({ part }) {\n * const {\n * filePath,\n * fileName,\n * content,\n * operationType,\n * isStreaming,\n * isCompleted,\n * isMarkdown,\n * } = useWriteTool({ part });\n *\n * if (isStreaming) {\n * return <div>Writing {fileName}...</div>;\n * }\n *\n * return (\n * <div>\n * <h3>{fileName} ({operationType})</h3>\n * {isMarkdown ? (\n * <MarkdownRenderer content={content} />\n * ) : (\n * <pre>{content}</pre>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useWriteTool({\n part,\n}: UseWriteToolOptions): UseWriteToolReturn {\n // Parse input data\n const inputData = useMemo((): WriteToolInput | null => {\n if (!part.input || typeof part.input !== \"object\") return null;\n const input = part.input as WriteToolInput;\n if (!input.file_path) return null;\n return input;\n }, [part.input]);\n\n // Parse output data\n const outputData = useMemo((): WriteToolOutput | null => {\n if (!part.output || typeof part.output !== \"object\") return null;\n const output = part.output as WriteToolOutput;\n if (!output.filePath) return null;\n return output;\n }, [part.output]);\n\n // Determine file path (prefer output, fallback to input)\n const filePath = outputData?.filePath ?? inputData?.file_path ?? null;\n\n // Extract file name\n const fileName = useMemo(() => {\n if (!filePath) return null;\n return filePath.split(\"/\").pop() || filePath;\n }, [filePath]);\n\n // Extract file extension\n const fileExtension = useMemo(() => {\n if (!fileName) return null;\n const parts = fileName.split(\".\");\n return parts.length > 1 ? parts.pop()?.toLowerCase() || null : null;\n }, [fileName]);\n\n // Determine content (prefer output, fallback to input)\n const content = outputData?.content ?? inputData?.content ?? null;\n\n // Operation type\n const operationType = outputData?.type ?? null;\n\n // Original content (for edits)\n const originalContent = outputData?.originalFile ?? null;\n\n // Structured patch\n const structuredPatch = outputData?.structuredPatch ?? null;\n\n // State parsing\n const state = useMemo((): UseWriteToolReturn[\"state\"] => {\n if (part.state === \"input-streaming\") return \"streaming\";\n if (part.state === \"output-error\") return \"error\";\n if (part.state === \"output-available\") return \"output-available\";\n return \"input-available\";\n }, [part.state]);\n\n const isStreaming = state === \"streaming\";\n const isCompleted = state === \"output-available\";\n const hasError = state === \"error\";\n const errorText = part.errorText ?? null;\n\n // Check if markdown\n const isMarkdown = useMemo(() => {\n if (!fileExtension) return false;\n return [\"md\", \"markdown\", \"mdx\"].includes(fileExtension);\n }, [fileExtension]);\n\n return {\n filePath,\n fileName,\n content,\n operationType,\n originalContent,\n structuredPatch,\n state,\n isStreaming,\n isCompleted,\n hasError,\n errorText,\n isMarkdown,\n fileExtension,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ArtifactData, UIMessage } from \"./types\";\n\n/**\n * Options for useArtifacts hook\n */\nexport interface UseArtifactsOptions {\n /** Messages to extract artifacts from */\n messages: UIMessage[];\n}\n\n/**\n * Return type for useArtifacts hook\n */\nexport interface UseArtifactsReturn {\n /** All extracted artifacts */\n artifacts: ArtifactData[];\n /** Currently selected artifact */\n selectedArtifact: ArtifactData | null;\n /** Set the selected artifact */\n setSelectedArtifact: (artifact: ArtifactData | null) => void;\n /** Select artifact by ID */\n selectArtifactById: (artifactId: string) => void;\n /** Whether there are any artifacts */\n hasArtifacts: boolean;\n /** Number of artifacts */\n count: number;\n /** Copy artifact content to clipboard */\n copyContent: (artifact: ArtifactData) => Promise<void>;\n /** Download artifact as file */\n downloadArtifact: (artifact: ArtifactData) => void;\n /** Get file extension from mime type */\n getFileExtension: (mimeType: string) => string;\n}\n\n/**\n * Get file extension from MIME type\n */\nfunction getFileExtensionFromMimeType(mimeType: string): string {\n const mimeToExtension: Record<string, string> = {\n \"text/plain\": \"txt\",\n \"text/html\": \"html\",\n \"text/css\": \"css\",\n \"text/javascript\": \"js\",\n \"text/markdown\": \"md\",\n \"application/json\": \"json\",\n \"application/xml\": \"xml\",\n \"application/pdf\": \"pdf\",\n \"image/png\": \"png\",\n \"image/jpeg\": \"jpg\",\n \"image/gif\": \"gif\",\n \"image/svg+xml\": \"svg\",\n };\n\n // Try exact match\n if (mimeToExtension[mimeType]) {\n return mimeToExtension[mimeType];\n }\n\n // Try partial match (e.g., \"text/x-markdown\" -> \"md\")\n if (mimeType.includes(\"markdown\")) return \"md\";\n if (mimeType.includes(\"json\")) return \"json\";\n if (mimeType.includes(\"javascript\")) return \"js\";\n if (mimeType.includes(\"typescript\")) return \"ts\";\n if (mimeType.includes(\"html\")) return \"html\";\n if (mimeType.includes(\"css\")) return \"css\";\n if (mimeType.includes(\"xml\")) return \"xml\";\n if (mimeType.includes(\"python\")) return \"py\";\n\n // Default\n return \"txt\";\n}\n\n/**\n * useArtifacts - Hook for managing artifacts from chat messages\n *\n * Extracts artifacts from messages and provides selection,\n * copy, and download functionality.\n *\n * @example\n * ```tsx\n * import { useArtifacts } from \"@sandagent/sdk/react\";\n *\n * function ArtifactPanel({ messages }) {\n * const {\n * artifacts,\n * selectedArtifact,\n * setSelectedArtifact,\n * hasArtifacts,\n * copyContent,\n * downloadArtifact,\n * } = useArtifacts({ messages });\n *\n * if (!hasArtifacts) return null;\n *\n * return (\n * <div>\n * {artifacts.map((artifact) => (\n * <button\n * key={artifact.artifactId}\n * onClick={() => setSelectedArtifact(artifact)}\n * >\n * {artifact.artifactId}\n * </button>\n * ))}\n *\n * {selectedArtifact && (\n * <div>\n * <pre>{selectedArtifact.content}</pre>\n * <button onClick={() => copyContent(selectedArtifact)}>Copy</button>\n * <button onClick={() => downloadArtifact(selectedArtifact)}>Download</button>\n * </div>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useArtifacts({\n messages,\n}: UseArtifactsOptions): UseArtifactsReturn {\n const [selectedArtifact, setSelectedArtifact] = useState<ArtifactData | null>(\n null,\n );\n\n // Extract artifacts from messages with memoization optimization\n const prevArtifactsRef = useRef<ArtifactData[]>([]);\n const artifacts = useMemo(() => {\n const results: ArtifactData[] = [];\n for (const message of messages) {\n for (const part of message.parts) {\n if (part.type === \"data-artifact\") {\n const data = part.data as ArtifactData;\n if (!results.some((a) => a.artifactId === data.artifactId)) {\n results.push(data);\n }\n }\n }\n }\n\n // Memoization optimization - return previous reference if content unchanged\n const prev = prevArtifactsRef.current;\n if (\n prev.length === results.length &&\n prev.every((prevArt, idx) => {\n const currArt = results[idx];\n return (\n prevArt.artifactId === currArt.artifactId &&\n prevArt.content === currArt.content &&\n prevArt.mimeType === currArt.mimeType\n );\n })\n ) {\n return prev;\n }\n\n prevArtifactsRef.current = results;\n return results;\n }, [messages]);\n\n // Sync selectedArtifact when artifacts change\n useEffect(() => {\n if (artifacts.length > 0) {\n setSelectedArtifact((prev) => {\n if (!prev) return artifacts[0];\n\n const currentMatch = artifacts.find(\n (a) => a.artifactId === prev.artifactId,\n );\n\n if (!currentMatch) {\n return artifacts[0];\n }\n\n if (\n currentMatch.content === prev.content &&\n currentMatch.mimeType === prev.mimeType\n ) {\n return prev;\n }\n\n return currentMatch;\n });\n } else {\n setSelectedArtifact((prev) => (prev === null ? prev : null));\n }\n }, [artifacts]);\n\n // Select artifact by ID\n const selectArtifactById = useCallback(\n (artifactId: string) => {\n const artifact = artifacts.find((a) => a.artifactId === artifactId);\n if (artifact) {\n setSelectedArtifact(artifact);\n }\n },\n [artifacts],\n );\n\n // Copy content to clipboard\n const copyContent = useCallback(async (artifact: ArtifactData) => {\n await navigator.clipboard.writeText(artifact.content);\n }, []);\n\n // Download artifact as file\n const downloadArtifact = useCallback((artifact: ArtifactData) => {\n const blob = new Blob([artifact.content], { type: artifact.mimeType });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n const fileName =\n artifact.artifactId.split(\"/\").pop() || artifact.artifactId;\n const extension = getFileExtensionFromMimeType(artifact.mimeType);\n a.download = fileName.includes(\".\") ? fileName : `${fileName}.${extension}`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n }, []);\n\n const hasArtifacts = artifacts.length > 0;\n const count = artifacts.length;\n\n return {\n artifacts,\n selectedArtifact,\n setSelectedArtifact,\n selectArtifactById,\n hasArtifacts,\n count,\n copyContent,\n downloadArtifact,\n getFileExtension: getFileExtensionFromMimeType,\n };\n}\n"],"mappings":"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","names":["useCallback","useMemo","useState","useMemo","useCallback","useEffect","useMemo","useRef","useState"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sandagent/sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "SandAgent SDK - AI Provider and React hooks for building AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -47,10 +47,9 @@
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@ai-sdk/provider": "^3.0.
|
|
51
|
-
"@ai-sdk/
|
|
52
|
-
"@
|
|
53
|
-
"@sandagent/manager": "0.2.2"
|
|
50
|
+
"@ai-sdk/provider": "^3.0.5",
|
|
51
|
+
"@ai-sdk/react": "^3.0.52",
|
|
52
|
+
"@sandagent/manager": "0.2.3"
|
|
54
53
|
},
|
|
55
54
|
"devDependencies": {
|
|
56
55
|
"@types/node": "^20.10.0",
|