@liveblocks/core 2.25.0-aiprivatebeta1 → 2.25.0-aiprivatebeta11

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 CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
 
7
7
  // src/version.ts
8
8
  var PKG_NAME = "@liveblocks/core";
9
- var PKG_VERSION = "2.25.0-aiprivatebeta1";
9
+ var PKG_VERSION = "2.25.0-aiprivatebeta11";
10
10
  var PKG_FORMAT = "esm";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -188,6 +188,9 @@ var warnWithTitle = wrapWithTitle("warn");
188
188
  var errorWithTitle = wrapWithTitle("error");
189
189
 
190
190
  // src/lib/guards.ts
191
+ function isDefined(value) {
192
+ return value !== null && value !== void 0;
193
+ }
191
194
  function isPlainObject(blob) {
192
195
  return blob !== null && typeof blob === "object" && Object.prototype.toString.call(blob) === "[object Object]";
193
196
  }
@@ -3685,11 +3688,6 @@ function parseAuthToken(rawTokenString) {
3685
3688
  function appendDelta(content, delta) {
3686
3689
  const lastPart = content[content.length - 1];
3687
3690
  switch (delta.type) {
3688
- case "reasoning":
3689
- case "text":
3690
- case "tool-call":
3691
- content.push(delta);
3692
- break;
3693
3691
  case "text-delta":
3694
3692
  if (lastPart?.type === "text") {
3695
3693
  lastPart.text += delta.textDelta;
@@ -3700,15 +3698,16 @@ function appendDelta(content, delta) {
3700
3698
  case "reasoning-delta":
3701
3699
  if (lastPart?.type === "reasoning") {
3702
3700
  lastPart.text += delta.textDelta;
3703
- lastPart.signature ??= delta.signature;
3704
3701
  } else {
3705
3702
  content.push({
3706
3703
  type: "reasoning",
3707
- text: delta.textDelta ?? "",
3708
- signature: delta.signature
3704
+ text: delta.textDelta ?? ""
3709
3705
  });
3710
3706
  }
3711
3707
  break;
3708
+ case "tool-invocation":
3709
+ content.push(delta);
3710
+ break;
3712
3711
  default:
3713
3712
  return assertNever(delta, "Unhandled case");
3714
3713
  }
@@ -3716,48 +3715,131 @@ function appendDelta(content, delta) {
3716
3715
 
3717
3716
  // src/ai.ts
3718
3717
  var DEFAULT_REQUEST_TIMEOUT = 4e3;
3719
- var DEFAULT_AI_TIMEOUT = 3e4;
3718
+ function defineAiTool() {
3719
+ return (def) => {
3720
+ return def;
3721
+ };
3722
+ }
3723
+ var KnowledgeStack = class {
3724
+ #_layers;
3725
+ #stack;
3726
+ // / \
3727
+ // knowledge key "layer" key
3728
+ // (random, or optionally (one entry per mounted component)
3729
+ // set by user)
3730
+ #_cache;
3731
+ constructor() {
3732
+ this.#_layers = /* @__PURE__ */ new Set();
3733
+ this.#stack = new DefaultMap(
3734
+ () => /* @__PURE__ */ new Map()
3735
+ );
3736
+ this.#_cache = void 0;
3737
+ }
3738
+ // Typically a useId()
3739
+ registerLayer(uniqueLayerId) {
3740
+ const layerKey = uniqueLayerId;
3741
+ if (this.#_layers.has(layerKey))
3742
+ raise(`Layer '${layerKey}' already exists, provide a unique layer id`);
3743
+ this.#_layers.add(layerKey);
3744
+ return layerKey;
3745
+ }
3746
+ deregisterLayer(layerKey) {
3747
+ this.#_layers.delete(layerKey);
3748
+ let deleted = false;
3749
+ for (const [key, knowledge] of this.#stack) {
3750
+ if (knowledge.delete(layerKey)) {
3751
+ deleted = true;
3752
+ }
3753
+ if (knowledge.size === 0)
3754
+ this.#stack.delete(key);
3755
+ }
3756
+ if (deleted) {
3757
+ this.invalidate();
3758
+ }
3759
+ }
3760
+ get() {
3761
+ return this.#_cache ??= this.#recompute();
3762
+ }
3763
+ invalidate() {
3764
+ this.#_cache = void 0;
3765
+ }
3766
+ #recompute() {
3767
+ return Array.from(this.#stack.values()).flatMap(
3768
+ (layer) => (
3769
+ // Return only the last item (returns [] when empty)
3770
+ Array.from(layer.values()).slice(-1).filter(isDefined)
3771
+ )
3772
+ );
3773
+ }
3774
+ updateKnowledge(layerKey, key, data) {
3775
+ if (!this.#_layers.has(layerKey)) raise(`Unknown layer key: ${layerKey}`);
3776
+ this.#stack.getOrCreate(key).set(layerKey, data);
3777
+ this.invalidate();
3778
+ }
3779
+ };
3720
3780
  function now() {
3721
3781
  return (/* @__PURE__ */ new Date()).toISOString();
3722
3782
  }
3783
+ var kWILDCARD = Symbol("*");
3723
3784
  function createStore_forTools() {
3724
- const toolsByChatId\u03A3 = new DefaultMap((_chatId) => {
3725
- return new DefaultMap((_toolName) => {
3726
- return new Signal(void 0);
3785
+ const toolsByChatId\u03A3 = new DefaultMap(
3786
+ (_chatId) => {
3787
+ return new DefaultMap((_name) => {
3788
+ return new Signal(void 0);
3789
+ });
3790
+ }
3791
+ );
3792
+ const globalOrScopedTool\u03A3 = new DefaultMap((nameAndChat) => {
3793
+ const [name, chatId] = tryParseJson(nameAndChat);
3794
+ return DerivedSignal.from(() => {
3795
+ return (
3796
+ // A tool that's registered and scoped to a specific chat ID...
3797
+ (chatId !== void 0 ? toolsByChatId\u03A3.get(chatId)?.get(name) : void 0)?.get() ?? // ...or a globally registered tool
3798
+ toolsByChatId\u03A3.getOrCreate(kWILDCARD).get(name)?.get()
3799
+ );
3727
3800
  });
3728
3801
  });
3729
- function getToolDefinition\u03A3(chatId, toolName) {
3730
- return toolsByChatId\u03A3.getOrCreate(chatId).getOrCreate(toolName);
3802
+ function getTool\u03A3(name, chatId) {
3803
+ const key = JSON.stringify(chatId !== void 0 ? [name, chatId] : [name]);
3804
+ return globalOrScopedTool\u03A3.getOrCreate(key);
3731
3805
  }
3732
- function addToolDefinition(chatId, name, definition) {
3733
- toolsByChatId\u03A3.getOrCreate(chatId).getOrCreate(name).set(definition);
3806
+ function registerTool(name, tool, chatId) {
3807
+ if (!tool.execute && !tool.render) {
3808
+ throw new Error(
3809
+ "A tool definition must have an execute() function, a render() function, or both."
3810
+ );
3811
+ }
3812
+ const key = chatId ?? kWILDCARD;
3813
+ toolsByChatId\u03A3.getOrCreate(key).getOrCreate(name).set(tool);
3814
+ return () => unregisterTool(key, name);
3734
3815
  }
3735
- function removeToolDefinition(chatId, toolName) {
3816
+ function unregisterTool(chatId, name) {
3736
3817
  const tools = toolsByChatId\u03A3.get(chatId);
3737
3818
  if (tools === void 0) return;
3738
- const tool = tools.get(toolName);
3819
+ const tool = tools.get(name);
3739
3820
  if (tool === void 0) return;
3740
3821
  tool.set(void 0);
3741
3822
  }
3742
- function getToolsForChat(chatId) {
3743
- const tools = toolsByChatId\u03A3.get(chatId);
3744
- if (tools === void 0) return [];
3745
- return Array.from(tools.entries()).map(([name, tool]) => {
3746
- if (tool.get() === void 0) return null;
3747
- return {
3748
- name,
3749
- definition: tool.get()
3750
- };
3751
- }).filter((tool) => tool !== null);
3823
+ function getToolDescriptions(chatId) {
3824
+ const globalTools\u03A3 = toolsByChatId\u03A3.get(kWILDCARD);
3825
+ const scopedTools\u03A3 = toolsByChatId\u03A3.get(chatId);
3826
+ return Array.from([
3827
+ ...globalTools\u03A3?.entries() ?? [],
3828
+ ...scopedTools\u03A3?.entries() ?? []
3829
+ ]).flatMap(([name, tool\u03A3]) => {
3830
+ const tool = tool\u03A3.get();
3831
+ return tool ? [{ name, description: tool.description, parameters: tool.parameters }] : [];
3832
+ });
3752
3833
  }
3753
3834
  return {
3754
- getToolCallByName\u03A3: getToolDefinition\u03A3,
3755
- getToolsForChat,
3756
- addToolDefinition,
3757
- removeToolDefinition
3835
+ getToolDescriptions,
3836
+ getTool\u03A3,
3837
+ registerTool
3758
3838
  };
3759
3839
  }
3760
- function createStore_forChatMessages() {
3840
+ function createStore_forChatMessages(toolsStore, setToolResult) {
3841
+ const autoExecutableMessages = /* @__PURE__ */ new Set();
3842
+ const seenToolCallIds = /* @__PURE__ */ new Set();
3761
3843
  const messagePoolByChatId\u03A3 = new DefaultMap(
3762
3844
  (_chatId) => new MutableSignal(
3763
3845
  new TreePool(
@@ -3767,7 +3849,7 @@ function createStore_forChatMessages() {
3767
3849
  )
3768
3850
  )
3769
3851
  );
3770
- const pendingMessages\u03A3 = new MutableSignal(
3852
+ const generatingMessages\u03A3 = new MutableSignal(
3771
3853
  /* @__PURE__ */ new Map()
3772
3854
  );
3773
3855
  function createOptimistically(chatId, role, parentId, third) {
@@ -3781,7 +3863,8 @@ function createStore_forChatMessages() {
3781
3863
  role,
3782
3864
  parentId,
3783
3865
  createdAt,
3784
- content
3866
+ content,
3867
+ _optimistic: true
3785
3868
  });
3786
3869
  } else {
3787
3870
  upsert({
@@ -3790,8 +3873,9 @@ function createStore_forChatMessages() {
3790
3873
  role,
3791
3874
  parentId,
3792
3875
  createdAt,
3793
- status: "pending",
3794
- contentSoFar: []
3876
+ status: "generating",
3877
+ contentSoFar: [],
3878
+ _optimistic: true
3795
3879
  });
3796
3880
  }
3797
3881
  return id;
@@ -3808,7 +3892,7 @@ function createStore_forChatMessages() {
3808
3892
  if (!chatMsgs\u03A3) return;
3809
3893
  const existing = chatMsgs\u03A3.get().get(messageId);
3810
3894
  if (!existing || existing.deletedAt) return;
3811
- if (existing.role === "assistant" && (existing.status === "pending" || existing.status === "failed")) {
3895
+ if (existing.role === "assistant" && existing.status !== "completed") {
3812
3896
  upsert({ ...existing, deletedAt: now(), contentSoFar: [] });
3813
3897
  } else {
3814
3898
  upsert({ ...existing, deletedAt: now(), content: [] });
@@ -3823,19 +3907,59 @@ function createStore_forChatMessages() {
3823
3907
  batch(() => {
3824
3908
  const chatMsgs\u03A3 = messagePoolByChatId\u03A3.getOrCreate(message.chatId);
3825
3909
  chatMsgs\u03A3.mutate((pool) => pool.upsert(message));
3826
- if (message.role === "assistant" && message.status === "pending") {
3827
- pendingMessages\u03A3.mutate((lut) => {
3910
+ if (message.role === "assistant" && message.status === "generating") {
3911
+ generatingMessages\u03A3.mutate((lut) => {
3828
3912
  lut.set(message.id, structuredClone(message));
3829
3913
  });
3830
3914
  } else {
3831
- pendingMessages\u03A3.mutate((lut) => {
3915
+ generatingMessages\u03A3.mutate((lut) => {
3832
3916
  lut.delete(message.id);
3833
3917
  });
3834
3918
  }
3919
+ if (message.role === "assistant" && message.status === "awaiting-tool") {
3920
+ for (const toolCall of message.contentSoFar.filter(
3921
+ (part) => part.type === "tool-invocation" && part.status === "executing"
3922
+ )) {
3923
+ if (seenToolCallIds.has(toolCall.toolCallId)) {
3924
+ continue;
3925
+ }
3926
+ seenToolCallIds.add(toolCall.toolCallId);
3927
+ const toolDef = toolsStore.getTool\u03A3(toolCall.toolName, message.chatId).get();
3928
+ const respondSync = (result) => {
3929
+ setToolResult(
3930
+ message.chatId,
3931
+ message.id,
3932
+ toolCall.toolCallId,
3933
+ result
3934
+ // TODO Pass in AiGenerationOptions here, or make the backend use the same options
3935
+ ).catch((err) => {
3936
+ error2(
3937
+ `Error trying to respond to tool-call: ${String(err)} (in respond())`
3938
+ );
3939
+ });
3940
+ };
3941
+ const executeFn = toolDef?.execute;
3942
+ if (executeFn && autoExecutableMessages.has(message.id)) {
3943
+ (async () => {
3944
+ const result = await executeFn(toolCall.args, {
3945
+ toolName: toolCall.toolName,
3946
+ toolCallId: toolCall.toolCallId
3947
+ });
3948
+ respondSync(result);
3949
+ })().catch((err) => {
3950
+ error2(
3951
+ `Error trying to respond to tool-call: ${String(err)} (in execute())`
3952
+ );
3953
+ });
3954
+ }
3955
+ }
3956
+ } else {
3957
+ autoExecutableMessages.delete(message.id);
3958
+ }
3835
3959
  });
3836
3960
  }
3837
3961
  function addDelta(messageId, delta) {
3838
- pendingMessages\u03A3.mutate((lut) => {
3962
+ generatingMessages\u03A3.mutate((lut) => {
3839
3963
  const message = lut.get(messageId);
3840
3964
  if (message === void 0) return false;
3841
3965
  appendDelta(message.contentSoFar, delta);
@@ -3843,10 +3967,10 @@ function createStore_forChatMessages() {
3843
3967
  return true;
3844
3968
  });
3845
3969
  }
3846
- function* iterPendingMessages() {
3970
+ function* iterGeneratingMessages() {
3847
3971
  for (const chatMsgs\u03A3 of messagePoolByChatId\u03A3.values()) {
3848
3972
  for (const m of chatMsgs\u03A3.get()) {
3849
- if (m.role === "assistant" && m.status === "pending") {
3973
+ if (m.role === "assistant" && m.status === "generating" && !m._optimistic) {
3850
3974
  yield m;
3851
3975
  }
3852
3976
  }
@@ -3854,9 +3978,18 @@ function createStore_forChatMessages() {
3854
3978
  }
3855
3979
  function failAllPending() {
3856
3980
  batch(() => {
3857
- pendingMessages\u03A3.mutate((lut) => lut.clear());
3981
+ generatingMessages\u03A3.mutate((lut) => {
3982
+ let deleted = false;
3983
+ for (const [k, v] of lut) {
3984
+ if (!v._optimistic) {
3985
+ lut.delete(k);
3986
+ deleted = true;
3987
+ }
3988
+ }
3989
+ return deleted;
3990
+ });
3858
3991
  upsertMany(
3859
- Array.from(iterPendingMessages()).map(
3992
+ Array.from(iterGeneratingMessages()).map(
3860
3993
  (message) => ({
3861
3994
  ...message,
3862
3995
  status: "failed",
@@ -3891,11 +4024,20 @@ function createStore_forChatMessages() {
3891
4024
  }
3892
4025
  function selectSpine(leaf) {
3893
4026
  const spine = [];
4027
+ let lastVisitedMessage = null;
3894
4028
  for (const message2 of pool.walkUp(leaf.id)) {
3895
4029
  const prev = first(pool.walkLeft(message2.id, isAlive))?.id ?? null;
3896
4030
  const next = first(pool.walkRight(message2.id, isAlive))?.id ?? null;
3897
4031
  if (!message2.deletedAt || prev || next) {
3898
- spine.push({ ...message2, prev, next });
4032
+ const node = {
4033
+ ...message2,
4034
+ navigation: { parent: null, prev, next }
4035
+ };
4036
+ if (lastVisitedMessage !== null) {
4037
+ lastVisitedMessage.navigation.parent = node.id;
4038
+ }
4039
+ lastVisitedMessage = node;
4040
+ spine.push(node);
3899
4041
  }
3900
4042
  }
3901
4043
  return spine.reverse();
@@ -3921,18 +4063,6 @@ function createStore_forChatMessages() {
3921
4063
  }
3922
4064
  return fallback();
3923
4065
  }
3924
- function getLatestUserMessageAncestor(chatId, messageId) {
3925
- const pool = messagePoolByChatId\u03A3.getOrCreate(chatId).get();
3926
- const message = pool.get(messageId);
3927
- if (!message) return null;
3928
- if (message.role === "user") return message.id;
3929
- for (const m of pool.walkUp(message.id)) {
3930
- if (m.role === "user" && !m.deletedAt) {
3931
- return m.id;
3932
- }
3933
- }
3934
- return null;
3935
- }
3936
4066
  const immutableMessagesByBranch = new DefaultMap((chatId) => {
3937
4067
  return new DefaultMap((branchId) => {
3938
4068
  const messages\u03A3 = DerivedSignal.from(() => {
@@ -3940,16 +4070,16 @@ function createStore_forChatMessages() {
3940
4070
  return selectBranch(pool, branchId);
3941
4071
  }, shallow2);
3942
4072
  return DerivedSignal.from(() => {
3943
- const pendingMessages = pendingMessages\u03A3.get();
4073
+ const generatingMessages = generatingMessages\u03A3.get();
3944
4074
  return messages\u03A3.get().map((message) => {
3945
- if (message.role !== "assistant" || message.status !== "pending") {
4075
+ if (message.role !== "assistant" || message.status !== "generating") {
3946
4076
  return message;
3947
4077
  }
3948
- const pendingMessage = pendingMessages.get(message.id);
3949
- if (pendingMessage === void 0) return message;
4078
+ const generatingMessage = generatingMessages.get(message.id);
4079
+ if (generatingMessage === void 0) return message;
3950
4080
  return {
3951
4081
  ...message,
3952
- contentSoFar: pendingMessage.contentSoFar
4082
+ contentSoFar: generatingMessage.contentSoFar
3953
4083
  };
3954
4084
  });
3955
4085
  }, shallow);
@@ -3958,21 +4088,10 @@ function createStore_forChatMessages() {
3958
4088
  function getChatMessagesForBranch\u03A3(chatId, branch) {
3959
4089
  return immutableMessagesByBranch.getOrCreate(chatId).getOrCreate(branch || null);
3960
4090
  }
3961
- const messagesByChatId\u03A3 = new DefaultMap((chatId) => {
3962
- return DerivedSignal.from(() => {
3963
- const pool = messagePoolByChatId\u03A3.getOrCreate(chatId).get();
3964
- return Array.from(pool.sorted);
3965
- });
3966
- });
3967
- function getMessagesForChat\u03A3(chatId) {
3968
- return messagesByChatId\u03A3.getOrCreate(chatId);
3969
- }
3970
4091
  return {
3971
4092
  // Readers
3972
4093
  getMessageById,
3973
4094
  getChatMessagesForBranch\u03A3,
3974
- getMessagesForChat\u03A3,
3975
- getLatestUserMessageAncestor,
3976
4095
  // Mutations
3977
4096
  createOptimistically,
3978
4097
  upsert,
@@ -3980,20 +4099,23 @@ function createStore_forChatMessages() {
3980
4099
  remove,
3981
4100
  removeByChatId,
3982
4101
  addDelta,
3983
- failAllPending
4102
+ failAllPending,
4103
+ allowAutoExecuteToolCall(messageId) {
4104
+ autoExecutableMessages.add(messageId);
4105
+ }
3984
4106
  };
3985
4107
  }
3986
4108
  function createStore_forUserAiChats() {
3987
- const mutable\u03A3 = new MutableSignal(
4109
+ const allChatsInclDeleted\u03A3 = new MutableSignal(
3988
4110
  SortedList.with((x, y) => y.createdAt < x.createdAt)
3989
4111
  );
3990
- const chats\u03A3 = DerivedSignal.from(
3991
- () => Array.from(mutable\u03A3.get()).filter((c) => !c.ephemeral && !c.deletedAt)
4112
+ const nonDeletedChats\u03A3 = DerivedSignal.from(
4113
+ () => Array.from(allChatsInclDeleted\u03A3.get()).filter((c) => !c.deletedAt)
3992
4114
  );
3993
4115
  function upsertMany(chats) {
3994
- mutable\u03A3.mutate((list) => {
4116
+ allChatsInclDeleted\u03A3.mutate((list) => {
3995
4117
  for (const chat of chats) {
3996
- remove(chat.id);
4118
+ list.removeBy((c) => c.id === chat.id, 1);
3997
4119
  list.add(chat);
3998
4120
  }
3999
4121
  });
@@ -4001,15 +4123,26 @@ function createStore_forUserAiChats() {
4001
4123
  function upsert(chat) {
4002
4124
  upsertMany([chat]);
4003
4125
  }
4004
- function remove(chatId) {
4005
- mutable\u03A3.mutate((list) => list.removeBy((c) => c.id === chatId, 1));
4126
+ function markDeleted(chatId) {
4127
+ allChatsInclDeleted\u03A3.mutate((list) => {
4128
+ const chat = list.find((c) => c.id === chatId);
4129
+ if (!chat) return false;
4130
+ upsert({ ...chat, deletedAt: now() });
4131
+ return void 0;
4132
+ });
4133
+ }
4134
+ function getChatById(chatId) {
4135
+ return Array.from(allChatsInclDeleted\u03A3.get()).find(
4136
+ (chat) => chat.id === chatId
4137
+ );
4006
4138
  }
4007
4139
  return {
4008
- chats\u03A3,
4140
+ chats\u03A3: nonDeletedChats\u03A3,
4141
+ getChatById,
4009
4142
  // Mutations
4010
4143
  upsert,
4011
4144
  upsertMany,
4012
- remove
4145
+ markDeleted
4013
4146
  };
4014
4147
  }
4015
4148
  function createAi(config) {
@@ -4019,10 +4152,9 @@ function createAi(config) {
4019
4152
  false
4020
4153
  // AI doesn't have actors (yet, but it will)
4021
4154
  );
4022
- const clientId = nanoid(7);
4023
4155
  const chatsStore = createStore_forUserAiChats();
4024
- const messagesStore = createStore_forChatMessages();
4025
4156
  const toolsStore = createStore_forTools();
4157
+ const messagesStore = createStore_forChatMessages(toolsStore, setToolResult);
4026
4158
  const context = {
4027
4159
  staticSessionInfoSig: new Signal(null),
4028
4160
  dynamicSessionInfoSig: new Signal(null),
@@ -4030,11 +4162,10 @@ function createAi(config) {
4030
4162
  chatsStore,
4031
4163
  messagesStore,
4032
4164
  toolsStore,
4033
- contextByChatId: /* @__PURE__ */ new Map()
4165
+ knowledge: new KnowledgeStack()
4034
4166
  };
4035
4167
  let lastTokenKey;
4036
- function onStatusDidChange(newStatus) {
4037
- warn("onStatusDidChange", newStatus);
4168
+ function onStatusDidChange(_newStatus) {
4038
4169
  const authValue = managedSocket.authValue;
4039
4170
  if (authValue !== null) {
4040
4171
  const tokenKey = getBearerTokenFromAuthValue(authValue);
@@ -4070,7 +4201,6 @@ function createAi(config) {
4070
4201
  }
4071
4202
  }
4072
4203
  function onDidConnect() {
4073
- warn("onDidConnect");
4074
4204
  }
4075
4205
  function onDidDisconnect() {
4076
4206
  warn("onDidDisconnect");
@@ -4112,7 +4242,7 @@ function createAi(config) {
4112
4242
  context.messagesStore.remove(m.chatId, m.id);
4113
4243
  }
4114
4244
  for (const chatId of msg["-chats"] ?? []) {
4115
- context.chatsStore.remove(chatId);
4245
+ context.chatsStore.markDeleted(chatId);
4116
4246
  context.messagesStore.removeByChatId(chatId);
4117
4247
  }
4118
4248
  for (const chatId of msg.clear ?? []) {
@@ -4134,34 +4264,36 @@ function createAi(config) {
4134
4264
  case "get-chats":
4135
4265
  context.chatsStore.upsertMany(msg.chats);
4136
4266
  break;
4137
- case "create-chat":
4267
+ case "get-or-create-chat":
4138
4268
  context.chatsStore.upsert(msg.chat);
4139
4269
  break;
4140
4270
  case "delete-chat":
4141
- context.chatsStore.remove(msg.chatId);
4271
+ context.chatsStore.markDeleted(msg.chatId);
4142
4272
  context.messagesStore.removeByChatId(msg.chatId);
4143
4273
  break;
4144
4274
  case "get-message-tree":
4145
4275
  context.chatsStore.upsert(msg.chat);
4146
4276
  context.messagesStore.upsertMany(msg.messages);
4147
4277
  break;
4148
- case "add-user-message":
4149
- context.messagesStore.upsert(msg.message);
4150
- break;
4151
4278
  case "delete-message":
4152
4279
  context.messagesStore.remove(msg.chatId, msg.messageId);
4153
4280
  break;
4154
4281
  case "clear-chat":
4155
4282
  context.messagesStore.removeByChatId(msg.chatId);
4156
4283
  break;
4157
- case "ask-ai":
4158
- if (msg.message) {
4159
- context.messagesStore.upsert(msg.message);
4160
- } else {
4284
+ case "ask-in-chat":
4285
+ if (msg.sourceMessage) {
4286
+ context.messagesStore.upsert(msg.sourceMessage);
4161
4287
  }
4288
+ context.messagesStore.upsert(msg.targetMessage);
4162
4289
  break;
4163
4290
  case "abort-ai":
4164
4291
  break;
4292
+ case "set-tool-result":
4293
+ if (msg.ok) {
4294
+ context.messagesStore.upsert(msg.message);
4295
+ }
4296
+ break;
4165
4297
  default:
4166
4298
  return assertNever(msg, "Unhandled case");
4167
4299
  }
@@ -4212,13 +4344,11 @@ function createAi(config) {
4212
4344
  cursor: options.cursor
4213
4345
  });
4214
4346
  }
4215
- function createChat(id, name, options) {
4347
+ function getOrCreateChat(id, options) {
4216
4348
  return sendClientMsgWithResponse({
4217
- cmd: "create-chat",
4349
+ cmd: "get-or-create-chat",
4218
4350
  id,
4219
- name,
4220
- ephemeral: options?.ephemeral ?? false,
4221
- metadata: options?.metadata ?? {}
4351
+ options
4222
4352
  });
4223
4353
  }
4224
4354
  function getMessageTree(chatId) {
@@ -4227,147 +4357,89 @@ function createAi(config) {
4227
4357
  chatId
4228
4358
  });
4229
4359
  }
4230
- function registerChatContext(chatId, data) {
4231
- const chatContext = context.contextByChatId.get(chatId);
4232
- if (chatContext === void 0) {
4233
- context.contextByChatId.set(chatId, /* @__PURE__ */ new Set([data]));
4234
- } else {
4235
- chatContext.add(data);
4236
- }
4237
- return () => {
4238
- const chatContext2 = context.contextByChatId.get(chatId);
4239
- if (chatContext2 !== void 0) {
4240
- chatContext2.delete(data);
4241
- if (chatContext2.size === 0) {
4242
- context.contextByChatId.delete(chatId);
4243
- }
4244
- }
4245
- };
4360
+ function registerKnowledgeLayer(uniqueLayerId) {
4361
+ return context.knowledge.registerLayer(uniqueLayerId);
4246
4362
  }
4247
- function ask(chatId, messageId, options) {
4248
- const targetMessageId = context.messagesStore.createOptimistically(
4249
- chatId,
4250
- "assistant",
4251
- messageId
4252
- );
4253
- const copilotId = options?.copilotId;
4254
- const stream = options?.stream ?? false;
4255
- const timeout = options?.timeout ?? DEFAULT_AI_TIMEOUT;
4256
- const chatContext = context.contextByChatId.get(chatId);
4257
- return sendClientMsgWithResponse({
4258
- cmd: "ask-ai",
4363
+ function deregisterKnowledgeLayer(layerKey) {
4364
+ context.knowledge.deregisterLayer(layerKey);
4365
+ }
4366
+ function updateKnowledge(layerKey, data, key = nanoid()) {
4367
+ context.knowledge.updateKnowledge(layerKey, key, data);
4368
+ }
4369
+ async function setToolResult(chatId, messageId, toolCallId, result, options) {
4370
+ const knowledge = context.knowledge.get();
4371
+ const tools = context.toolsStore.getToolDescriptions(chatId);
4372
+ const resp = await sendClientMsgWithResponse({
4373
+ cmd: "set-tool-result",
4259
4374
  chatId,
4260
- sourceMessageId: messageId,
4261
- targetMessageId,
4262
- copilotId,
4263
- clientId,
4264
- stream,
4265
- tools: context.toolsStore.getToolsForChat(chatId).map((tool) => ({
4266
- name: tool.name,
4267
- description: tool.definition.description,
4268
- parameters: tool.definition.parameters
4269
- })),
4270
- timeout,
4271
- context: chatContext ? Array.from(chatContext.values()) : void 0
4375
+ messageId,
4376
+ toolCallId,
4377
+ result,
4378
+ generationOptions: {
4379
+ copilotId: options?.copilotId,
4380
+ stream: options?.stream,
4381
+ timeout: options?.timeout,
4382
+ // Knowledge and tools aren't coming from the options, but retrieved
4383
+ // from the global context
4384
+ knowledge: knowledge.length > 0 ? knowledge : void 0,
4385
+ tools: tools.length > 0 ? tools : void 0
4386
+ }
4272
4387
  });
4388
+ if (resp.ok) {
4389
+ messagesStore.allowAutoExecuteToolCall(resp.message.id);
4390
+ }
4391
+ return resp;
4273
4392
  }
4274
4393
  return Object.defineProperty(
4275
4394
  {
4276
4395
  [kInternal]: {
4277
- debugContext: () => context
4396
+ context
4278
4397
  },
4279
4398
  connect: () => managedSocket.connect(),
4280
4399
  reconnect: () => managedSocket.reconnect(),
4281
4400
  disconnect: () => managedSocket.disconnect(),
4282
4401
  getChats,
4283
- createChat,
4402
+ getOrCreateChat,
4284
4403
  deleteChat: (chatId) => {
4285
- return sendClientMsgWithResponse({
4286
- cmd: "delete-chat",
4287
- chatId
4288
- });
4404
+ return sendClientMsgWithResponse({ cmd: "delete-chat", chatId });
4289
4405
  },
4290
4406
  getMessageTree,
4291
4407
  deleteMessage: (chatId, messageId) => sendClientMsgWithResponse({ cmd: "delete-message", chatId, messageId }),
4292
4408
  clearChat: (chatId) => sendClientMsgWithResponse({ cmd: "clear-chat", chatId }),
4293
- addUserMessage: (chatId, parentMessageId, message) => {
4294
- const content = [{ type: "text", text: message }];
4295
- const newMessageId = context.messagesStore.createOptimistically(
4296
- chatId,
4297
- "user",
4298
- parentMessageId,
4299
- content
4300
- );
4301
- return sendClientMsgWithResponse({
4302
- cmd: "add-user-message",
4303
- id: newMessageId,
4409
+ askUserMessageInChat: async (chatId, userMessage, targetMessageId, options) => {
4410
+ const knowledge = context.knowledge.get();
4411
+ const tools = context.toolsStore.getToolDescriptions(chatId);
4412
+ const resp = await sendClientMsgWithResponse({
4413
+ cmd: "ask-in-chat",
4304
4414
  chatId,
4305
- parentMessageId,
4306
- content
4307
- });
4308
- },
4309
- ask,
4310
- regenerateMessage: (chatId, messageId, options) => {
4311
- const parentUserMessageId = context.messagesStore.getLatestUserMessageAncestor(chatId, messageId);
4312
- if (parentUserMessageId === null) {
4313
- throw new Error(
4314
- `Unable to find user message ancestor for messageId: ${messageId}`
4315
- );
4316
- }
4317
- return ask(chatId, parentUserMessageId, options);
4318
- },
4319
- addUserMessageAndAsk: async (chatId, parentMessageId, message, options) => {
4320
- const content = [{ type: "text", text: message }];
4321
- const newMessageId = context.messagesStore.createOptimistically(
4322
- chatId,
4323
- "user",
4324
- parentMessageId,
4325
- content
4326
- );
4327
- const targetMessageId = context.messagesStore.createOptimistically(
4328
- chatId,
4329
- "assistant",
4330
- newMessageId
4331
- );
4332
- await sendClientMsgWithResponse({
4333
- cmd: "add-user-message",
4334
- id: newMessageId,
4335
- chatId,
4336
- parentMessageId,
4337
- content
4338
- });
4339
- const copilotId = options?.copilotId;
4340
- const stream = options?.stream ?? false;
4341
- const timeout = options?.timeout ?? DEFAULT_AI_TIMEOUT;
4342
- const chatContext = context.contextByChatId.get(chatId);
4343
- return sendClientMsgWithResponse({
4344
- cmd: "ask-ai",
4345
- chatId,
4346
- sourceMessageId: newMessageId,
4415
+ sourceMessage: userMessage,
4347
4416
  targetMessageId,
4348
- copilotId,
4349
- clientId,
4350
- stream,
4351
- tools: context.toolsStore.getToolsForChat(chatId).map((tool) => ({
4352
- name: tool.name,
4353
- description: tool.definition.description,
4354
- parameters: tool.definition.parameters
4355
- })),
4356
- timeout,
4357
- context: chatContext ? Array.from(chatContext.values()) : void 0
4417
+ generationOptions: {
4418
+ copilotId: options?.copilotId,
4419
+ stream: options?.stream,
4420
+ timeout: options?.timeout,
4421
+ // Knowledge and tools aren't coming from the options, but retrieved
4422
+ // from the global context
4423
+ knowledge: knowledge.length > 0 ? knowledge : void 0,
4424
+ tools: tools.length > 0 ? tools : void 0
4425
+ }
4358
4426
  });
4427
+ messagesStore.allowAutoExecuteToolCall(resp.targetMessage.id);
4428
+ return resp;
4359
4429
  },
4360
4430
  abort: (messageId) => sendClientMsgWithResponse({ cmd: "abort-ai", messageId }),
4431
+ setToolResult,
4361
4432
  getStatus: () => managedSocket.getStatus(),
4362
4433
  signals: {
4363
4434
  chats\u03A3: context.chatsStore.chats\u03A3,
4364
4435
  getChatMessagesForBranch\u03A3: context.messagesStore.getChatMessagesForBranch\u03A3,
4365
- getToolDefinition\u03A3: context.toolsStore.getToolCallByName\u03A3,
4366
- getMessagesForChat\u03A3: context.messagesStore.getMessagesForChat\u03A3
4436
+ getTool\u03A3: context.toolsStore.getTool\u03A3
4367
4437
  },
4368
- registerChatContext,
4369
- registerChatTool: context.toolsStore.addToolDefinition,
4370
- unregisterChatTool: context.toolsStore.removeToolDefinition
4438
+ getChatById: context.chatsStore.getChatById,
4439
+ registerKnowledgeLayer,
4440
+ deregisterKnowledgeLayer,
4441
+ updateKnowledge,
4442
+ registerTool: context.toolsStore.registerTool
4371
4443
  },
4372
4444
  kInternal,
4373
4445
  { enumerable: false }
@@ -10531,6 +10603,7 @@ export {
10531
10603
  createManagedPool,
10532
10604
  createNotificationSettings,
10533
10605
  createThreadId,
10606
+ defineAiTool,
10534
10607
  deprecate,
10535
10608
  deprecateIf,
10536
10609
  detectDupes,