anthropic.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import { get, writable } from 'svelte/store';
  2. import { browser } from '$app/environment'
  3. import { aiActivity } from '$lib/activities.js'
  4. import Anthropic from '@anthropic-ai/sdk';
  5. var client = null;
  6. var messages = [];
  7. export function setApiKey(key)
  8. {
  9. client = new Anthropic({apiKey: key, dangerouslyAllowBrowser: true});
  10. // Reset messages
  11. messages = []
  12. messageList.set(messages);
  13. localStorage.setItem("anthropic-api-key", key);
  14. apiState.set("READY");
  15. plausible("ClaudeAI Key");
  16. }
  17. function clearApiKey()
  18. {
  19. localStorage.removeItem("anthropic-api-key");
  20. apiState.set("KEY_REQUIRED");
  21. }
  22. function addMessageInternal(role, content)
  23. {
  24. messages.push({role: role, content: content});
  25. messageList.set(messages);
  26. }
  27. async function sendMessages(handleTool)
  28. {
  29. aiActivity.set(true);
  30. try
  31. {
  32. var dc = get(displayConfig);
  33. var tool = dc ? { type: "computer_20241022", name: "computer", display_width_px: dc.width, display_height_px: dc.height } : { type: "bash_20241022", name: "bash" }
  34. const response = await client.beta.messages.create({max_tokens: 1024, messages: messages, model: 'claude-3-5-sonnet-20241022', tools: [tool], betas: ["computer-use-2024-10-22"]});
  35. // Remove all the image payloads, we don't want to send them over and over again
  36. for(var i=0;i<messages.length;i++)
  37. {
  38. var c = messages[i].content;
  39. if(Array.isArray(c))
  40. {
  41. if(c[0].type == "tool_result" && c[0].content && c[0].content[0].type == "image")
  42. delete c[0].content;
  43. }
  44. }
  45. var content = response.content;
  46. // Be robust to multiple response
  47. for(var i=0;i<content.length;i++)
  48. {
  49. var c = content[i];
  50. if(c.type == "text")
  51. {
  52. addMessageInternal(response.role, c.text);
  53. }
  54. else if(c.type == "tool_use")
  55. {
  56. addMessageInternal(response.role, [c]);
  57. var commandResponse = await handleTool(c.input);
  58. var responseObj = {type: "tool_result", tool_use_id: c.id };
  59. if(commandResponse != null)
  60. {
  61. if(commandResponse instanceof Error)
  62. {
  63. console.warn(`Tool error: ${commandResponse.message}`);
  64. responseObj.content = commandResponse.message;
  65. responseObj.is_error = true;
  66. }
  67. else
  68. {
  69. responseObj.content = commandResponse;
  70. }
  71. }
  72. addMessageInternal("user", [responseObj]);
  73. sendMessages(handleTool);
  74. }
  75. else
  76. {
  77. console.warn(`Invalid response type: ${c.type}`);
  78. }
  79. }
  80. if(response.stop_reason == "end_turn")
  81. aiActivity.set(false);
  82. }
  83. catch(e)
  84. {
  85. if(e.status == 401)
  86. {
  87. addMessageInternal('error', 'Invalid API key');
  88. clearApiKey();
  89. }
  90. else
  91. {
  92. addMessageInternal('error', e.error.error.message);
  93. }
  94. }
  95. }
  96. export function addMessage(text, handleTool)
  97. {
  98. addMessageInternal('user', text);
  99. sendMessages(handleTool);
  100. plausible("ClaudeAI Use");
  101. }
  102. function initialize()
  103. {
  104. var savedApiKey = localStorage.getItem("anthropic-api-key");
  105. if(savedApiKey)
  106. setApiKey(savedApiKey);
  107. }
  108. export const apiState = writable("KEY_REQUIRED");
  109. export const messageList = writable(messages);
  110. export const currentMessage = writable("");
  111. export const displayConfig = writable(null);
  112. if(browser)
  113. initialize();