@avee1234/agent-kit 0.2.0 → 0.3.1

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
@@ -64,7 +64,15 @@ var OpenAICompatibleAdapter = class {
64
64
  function: {
65
65
  name: t.name,
66
66
  description: t.description,
67
- parameters: { type: "object", properties: t.parameters }
67
+ parameters: {
68
+ type: "object",
69
+ properties: Object.fromEntries(
70
+ Object.entries(t.parameters).map(([key, val]) => {
71
+ const { required: _req, ...rest } = val;
72
+ return [key, rest];
73
+ })
74
+ )
75
+ }
68
76
  }
69
77
  }));
70
78
  }
@@ -110,7 +118,15 @@ var OpenAICompatibleAdapter = class {
110
118
  function: {
111
119
  name: t.name,
112
120
  description: t.description,
113
- parameters: { type: "object", properties: t.parameters }
121
+ parameters: {
122
+ type: "object",
123
+ properties: Object.fromEntries(
124
+ Object.entries(t.parameters).map(([key, val]) => {
125
+ const { required: _req, ...rest } = val;
126
+ return [key, rest];
127
+ })
128
+ )
129
+ }
114
130
  }
115
131
  }));
116
132
  }
@@ -572,13 +588,11 @@ var HierarchicalStrategy = class {
572
588
  parameters: {
573
589
  agentName: {
574
590
  type: "string",
575
- description: "The name of the agent to delegate to",
576
- required: true
591
+ description: `The name of the agent to delegate to. Available: ${[...agents.map((a) => a.name)].join(", ")}`
577
592
  },
578
593
  task: {
579
594
  type: "string",
580
- description: "The task to assign to the agent",
581
- required: true
595
+ description: "The task to assign to the agent"
582
596
  }
583
597
  },
584
598
  execute: async (params) => {
@@ -687,10 +701,27 @@ var Team = class {
687
701
  }
688
702
  };
689
703
 
704
+ // src/store/cosine.ts
705
+ function cosineSimilarity(a, b) {
706
+ let dot = 0;
707
+ let normA = 0;
708
+ let normB = 0;
709
+ for (let i = 0; i < a.length; i++) {
710
+ dot += a[i] * b[i];
711
+ normA += a[i] * a[i];
712
+ normB += b[i] * b[i];
713
+ }
714
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
715
+ if (denom === 0) return 0;
716
+ return dot / denom;
717
+ }
718
+
690
719
  // src/store/in-memory.ts
691
720
  var InMemoryStore = class {
692
721
  messages = /* @__PURE__ */ new Map();
693
722
  summaries = /* @__PURE__ */ new Map();
723
+ // agentId -> (summaryId -> embedding vector)
724
+ embeddings = /* @__PURE__ */ new Map();
694
725
  async saveMessages(agentId, messages) {
695
726
  const existing = this.messages.get(agentId) ?? [];
696
727
  existing.push(...messages);
@@ -711,6 +742,28 @@ var InMemoryStore = class {
711
742
  const matches = all.filter((s) => s.content.toLowerCase().includes(queryLower)).sort((a, b) => b.timestamp - a.timestamp).slice(0, limit);
712
743
  return matches;
713
744
  }
745
+ async saveEmbedding(agentId, summaryId, embedding) {
746
+ let agentMap = this.embeddings.get(agentId);
747
+ if (!agentMap) {
748
+ agentMap = /* @__PURE__ */ new Map();
749
+ this.embeddings.set(agentId, agentMap);
750
+ }
751
+ agentMap.set(summaryId, embedding);
752
+ }
753
+ async searchByEmbedding(agentId, embedding, limit) {
754
+ const agentMap = this.embeddings.get(agentId);
755
+ if (!agentMap || agentMap.size === 0) return [];
756
+ const summaries = this.summaries.get(agentId) ?? [];
757
+ const summaryById = new Map(summaries.map((s) => [s.id, s]));
758
+ const scored = [];
759
+ for (const [summaryId, storedEmbedding] of agentMap) {
760
+ const summary = summaryById.get(summaryId);
761
+ if (!summary) continue;
762
+ const score = cosineSimilarity(embedding, storedEmbedding);
763
+ scored.push({ summary, score });
764
+ }
765
+ return scored.sort((a, b) => b.score - a.score).slice(0, limit).map((entry) => entry.summary);
766
+ }
714
767
  };
715
768
 
716
769
  // src/store/sqlite.ts
@@ -743,8 +796,14 @@ var SQLiteStore = class {
743
796
  message_range_from INTEGER NOT NULL,
744
797
  message_range_to INTEGER NOT NULL
745
798
  );
799
+ CREATE TABLE IF NOT EXISTS embeddings (
800
+ summary_id TEXT PRIMARY KEY,
801
+ agent_id TEXT NOT NULL,
802
+ embedding BLOB NOT NULL
803
+ );
746
804
  CREATE INDEX IF NOT EXISTS idx_messages_agent ON messages(agent_id);
747
805
  CREATE INDEX IF NOT EXISTS idx_summaries_agent ON summaries(agent_id);
806
+ CREATE INDEX IF NOT EXISTS idx_embeddings_agent ON embeddings(agent_id);
748
807
  `);
749
808
  }
750
809
  async saveMessages(agentId, messages) {
@@ -804,25 +863,208 @@ var SQLiteStore = class {
804
863
  messageRange: { from: row.message_range_from, to: row.message_range_to }
805
864
  }));
806
865
  }
866
+ async saveEmbedding(agentId, summaryId, embedding) {
867
+ this.db.prepare(
868
+ "INSERT OR REPLACE INTO embeddings (summary_id, agent_id, embedding) VALUES (?, ?, ?)"
869
+ ).run(summaryId, agentId, JSON.stringify(embedding));
870
+ }
871
+ async searchByEmbedding(agentId, embedding, limit) {
872
+ const rows = this.db.prepare(
873
+ `SELECT e.summary_id, s.content, s.timestamp, s.message_range_from, s.message_range_to, e.embedding
874
+ FROM embeddings e
875
+ JOIN summaries s ON e.summary_id = s.id
876
+ WHERE e.agent_id = ?`
877
+ ).all(agentId);
878
+ if (rows.length === 0) return [];
879
+ const scored = rows.map((row) => {
880
+ const storedEmbedding = JSON.parse(row.embedding);
881
+ const score = cosineSimilarity(embedding, storedEmbedding);
882
+ return {
883
+ summary: {
884
+ id: row.summary_id,
885
+ content: row.content,
886
+ timestamp: row.timestamp,
887
+ messageRange: { from: row.message_range_from, to: row.message_range_to }
888
+ },
889
+ score
890
+ };
891
+ });
892
+ return scored.sort((a, b) => b.score - a.score).slice(0, limit).map((entry) => entry.summary);
893
+ }
807
894
  close() {
808
895
  this.db.close();
809
896
  }
810
897
  };
811
898
 
899
+ // src/store/postgres.ts
900
+ import { createRequire as createRequire2 } from "module";
901
+ var require3 = createRequire2(import.meta.url);
902
+ var SCHEMA_SQL = `
903
+ CREATE EXTENSION IF NOT EXISTS vector;
904
+
905
+ CREATE TABLE IF NOT EXISTS agent_messages (
906
+ id SERIAL PRIMARY KEY,
907
+ agent_id TEXT NOT NULL,
908
+ role TEXT NOT NULL,
909
+ content TEXT NOT NULL,
910
+ timestamp BIGINT NOT NULL,
911
+ tool_calls JSONB,
912
+ tool_call_id TEXT
913
+ );
914
+
915
+ CREATE TABLE IF NOT EXISTS agent_summaries (
916
+ id TEXT PRIMARY KEY,
917
+ agent_id TEXT NOT NULL,
918
+ content TEXT NOT NULL,
919
+ timestamp BIGINT NOT NULL,
920
+ message_range_from BIGINT NOT NULL,
921
+ message_range_to BIGINT NOT NULL,
922
+ embedding vector(768)
923
+ );
924
+
925
+ CREATE INDEX IF NOT EXISTS idx_agent_messages_agent ON agent_messages(agent_id);
926
+ CREATE INDEX IF NOT EXISTS idx_agent_summaries_agent ON agent_summaries(agent_id);
927
+ `;
928
+ var PostgresStore = class _PostgresStore {
929
+ pool;
930
+ constructor(config) {
931
+ const { Pool } = require3("pg");
932
+ this.pool = new Pool({ connectionString: config.connectionString });
933
+ void this.init();
934
+ }
935
+ async init() {
936
+ await this.pool.query(SCHEMA_SQL);
937
+ }
938
+ /** Factory that ensures schema is ready before returning the store. */
939
+ static async create(config) {
940
+ const store = new _PostgresStore(config);
941
+ await store.init();
942
+ return store;
943
+ }
944
+ async saveMessages(agentId, messages) {
945
+ for (const msg of messages) {
946
+ await this.pool.query(
947
+ `INSERT INTO agent_messages (agent_id, role, content, timestamp, tool_calls, tool_call_id)
948
+ VALUES ($1, $2, $3, $4, $5, $6)`,
949
+ [
950
+ agentId,
951
+ msg.role,
952
+ msg.content,
953
+ msg.timestamp,
954
+ msg.toolCalls ? JSON.stringify(msg.toolCalls) : null,
955
+ msg.toolCallId ?? null
956
+ ]
957
+ );
958
+ }
959
+ }
960
+ async getRecentMessages(agentId, limit) {
961
+ const result = await this.pool.query(
962
+ `SELECT role, content, timestamp, tool_calls, tool_call_id
963
+ FROM agent_messages
964
+ WHERE agent_id = $1
965
+ ORDER BY id DESC
966
+ LIMIT $2`,
967
+ [agentId, limit]
968
+ );
969
+ return result.rows.reverse().map((row) => ({
970
+ role: row.role,
971
+ content: row.content,
972
+ timestamp: Number(row.timestamp),
973
+ ...row.tool_calls ? {
974
+ toolCalls: typeof row.tool_calls === "string" ? JSON.parse(row.tool_calls) : row.tool_calls
975
+ } : {},
976
+ ...row.tool_call_id ? { toolCallId: row.tool_call_id } : {}
977
+ }));
978
+ }
979
+ async saveSummary(agentId, summary) {
980
+ await this.pool.query(
981
+ `INSERT INTO agent_summaries (id, agent_id, content, timestamp, message_range_from, message_range_to)
982
+ VALUES ($1, $2, $3, $4, $5, $6)`,
983
+ [
984
+ summary.id,
985
+ agentId,
986
+ summary.content,
987
+ summary.timestamp,
988
+ summary.messageRange.from,
989
+ summary.messageRange.to
990
+ ]
991
+ );
992
+ }
993
+ async searchSummaries(agentId, query, limit) {
994
+ const result = await this.pool.query(
995
+ `SELECT id, content, timestamp, message_range_from, message_range_to
996
+ FROM agent_summaries
997
+ WHERE agent_id = $1 AND content ILIKE $2
998
+ ORDER BY timestamp DESC
999
+ LIMIT $3`,
1000
+ [agentId, `%${query}%`, limit]
1001
+ );
1002
+ return result.rows.map((row) => ({
1003
+ id: row.id,
1004
+ content: row.content,
1005
+ timestamp: Number(row.timestamp),
1006
+ messageRange: {
1007
+ from: Number(row.message_range_from),
1008
+ to: Number(row.message_range_to)
1009
+ }
1010
+ }));
1011
+ }
1012
+ async saveEmbedding(agentId, summaryId, embedding) {
1013
+ const vectorLiteral = `[${embedding.join(",")}]`;
1014
+ await this.pool.query(
1015
+ `UPDATE agent_summaries SET embedding = $1 WHERE id = $2 AND agent_id = $3`,
1016
+ [vectorLiteral, summaryId, agentId]
1017
+ );
1018
+ }
1019
+ async searchByEmbedding(agentId, embedding, limit) {
1020
+ const vectorLiteral = `[${embedding.join(",")}]`;
1021
+ const result = await this.pool.query(
1022
+ `SELECT id, content, timestamp, message_range_from, message_range_to
1023
+ FROM agent_summaries
1024
+ WHERE agent_id = $1 AND embedding IS NOT NULL
1025
+ ORDER BY embedding <=> $2
1026
+ LIMIT $3`,
1027
+ [agentId, vectorLiteral, limit]
1028
+ );
1029
+ return result.rows.map((row) => ({
1030
+ id: row.id,
1031
+ content: row.content,
1032
+ timestamp: Number(row.timestamp),
1033
+ messageRange: {
1034
+ from: Number(row.message_range_from),
1035
+ to: Number(row.message_range_to)
1036
+ }
1037
+ }));
1038
+ }
1039
+ async close() {
1040
+ await this.pool.end();
1041
+ }
1042
+ };
1043
+
812
1044
  // src/memory.ts
813
1045
  var Memory = class {
814
1046
  store;
815
1047
  windowSize;
816
1048
  summarizeAfter;
817
1049
  model;
1050
+ embeddingAdapter;
818
1051
  messageCount = /* @__PURE__ */ new Map();
819
1052
  constructor(config = {}) {
820
1053
  this.windowSize = config.windowSize ?? 20;
821
1054
  this.summarizeAfter = config.summarizeAfter ?? 20;
1055
+ this.embeddingAdapter = config.embedding;
822
1056
  if (!config.store || config.store === "memory") {
823
1057
  this.store = new InMemoryStore();
824
1058
  } else if (config.store === "sqlite") {
825
1059
  this.store = new SQLiteStore(config.path ?? "./agent-memory.db");
1060
+ } else if (config.store === "postgres") {
1061
+ const connectionString = config.url ?? config.path;
1062
+ if (!connectionString) {
1063
+ throw new Error(
1064
+ "Memory store 'postgres' requires a connection string via the 'url' config option."
1065
+ );
1066
+ }
1067
+ this.store = new PostgresStore({ connectionString });
826
1068
  } else {
827
1069
  this.store = config.store;
828
1070
  }
@@ -844,7 +1086,13 @@ var Memory = class {
844
1086
  }
845
1087
  async getContext(agentId, query) {
846
1088
  const recentMessages = await this.store.getRecentMessages(agentId, this.windowSize);
847
- const relevantSummaries = await this.store.searchSummaries(agentId, query, 3);
1089
+ let relevantSummaries;
1090
+ if (this.embeddingAdapter && this.store.searchByEmbedding) {
1091
+ const queryEmbedding = await this.embeddingAdapter.embed(query);
1092
+ relevantSummaries = await this.store.searchByEmbedding(agentId, queryEmbedding, 3);
1093
+ } else {
1094
+ relevantSummaries = await this.store.searchSummaries(agentId, query, 3);
1095
+ }
848
1096
  return { recentMessages, relevantSummaries };
849
1097
  }
850
1098
  async summarize(agentId) {
@@ -867,6 +1115,10 @@ var Memory = class {
867
1115
  }
868
1116
  });
869
1117
  await this.store.saveSummary(agentId, summary);
1118
+ if (this.embeddingAdapter && this.store.saveEmbedding) {
1119
+ const embedding = await this.embeddingAdapter.embed(summary.content);
1120
+ await this.store.saveEmbedding(agentId, summary.id, embedding);
1121
+ }
870
1122
  }
871
1123
  close() {
872
1124
  if ("close" in this.store && typeof this.store.close === "function") {
@@ -874,13 +1126,45 @@ var Memory = class {
874
1126
  }
875
1127
  }
876
1128
  };
1129
+
1130
+ // src/model/ollama-embedding.ts
1131
+ var OllamaEmbeddingAdapter = class {
1132
+ baseURL;
1133
+ model;
1134
+ constructor(config = {}) {
1135
+ this.baseURL = config.baseURL ?? "http://localhost:11434";
1136
+ this.model = config.model ?? "nomic-embed-text";
1137
+ }
1138
+ async embed(text) {
1139
+ const [vector] = await this.request(text);
1140
+ return vector;
1141
+ }
1142
+ async embedBatch(texts) {
1143
+ if (texts.length === 0) return [];
1144
+ return this.request(texts);
1145
+ }
1146
+ async request(input) {
1147
+ const response = await fetch(`${this.baseURL}/api/embed`, {
1148
+ method: "POST",
1149
+ headers: { "Content-Type": "application/json" },
1150
+ body: JSON.stringify({ model: this.model, input })
1151
+ });
1152
+ if (!response.ok) {
1153
+ throw new Error(`Ollama embedding request failed: ${response.status} ${response.statusText}`);
1154
+ }
1155
+ const data = await response.json();
1156
+ return data.embeddings;
1157
+ }
1158
+ };
877
1159
  export {
878
1160
  Agent,
879
1161
  AgentEventEmitter,
880
1162
  InMemoryStore,
881
1163
  Memory,
882
1164
  MockAdapter,
1165
+ OllamaEmbeddingAdapter,
883
1166
  OpenAICompatibleAdapter,
1167
+ PostgresStore,
884
1168
  SQLiteStore,
885
1169
  Team,
886
1170
  Tool,