diff --git a/components/brillium/brillium.app.mjs b/components/brillium/brillium.app.mjs index d324fcb1d31d4..318c547227b06 100644 --- a/components/brillium/brillium.app.mjs +++ b/components/brillium/brillium.app.mjs @@ -8,4 +8,4 @@ export default { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/zep/actions/add-memory/add-memory.mjs b/components/zep/actions/add-memory/add-memory.mjs new file mode 100644 index 0000000000000..b4111f01e514e --- /dev/null +++ b/components/zep/actions/add-memory/add-memory.mjs @@ -0,0 +1,55 @@ +import zep from "../../zep.app.mjs"; +import utils from "../../common/utils.mjs"; + +export default { + key: "zep-add-memory", + name: "Add Memory to Session", + description: "Adds memory to an existing session in Zep. [See the documentation](https://help.getzep.com/api-reference/memory/add)", + version: "0.0.1", + type: "action", + props: { + zep, + sessionId: { + propDefinition: [ + zep, + "sessionId", + ], + }, + messages: { + type: "string[]", + label: "Messages", + description: "An array of message objects, where each message contains a role (`norole`, `system`, `assistant`, `user`, `function`, or `tool`) and content. Example: `[{ \"content\": \"content\", \"role_type\": \"norole\" }]` [See the documentation](https://help.getzep.com/api-reference/memory/add) for more information", + }, + factInstruction: { + type: "string", + label: "Fact Instruction", + description: "Additional instruction for generating the facts", + optional: true, + }, + returnContext: { + type: "boolean", + label: "Return Context", + description: "Optionally return memory context relevant to the most recent messages", + optional: true, + }, + summaryInstruction: { + type: "string", + label: "Summary Instructions", + description: "Additional instruction for generating the summary", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.zep.addMemoryToSession({ + sessionId: this.sessionId, + data: { + messages: utils.parseArray(this.messages), + factInstruction: this.factInstruction, + returnContext: this.returnContext, + summaryInstruction: this.summaryInstruction, + }, + }); + $.export("$summary", `Added memory to session ${this.sessionId}`); + return response; + }, +}; diff --git a/components/zep/actions/add-user/add-user.mjs b/components/zep/actions/add-user/add-user.mjs new file mode 100644 index 0000000000000..85e30feec2b86 --- /dev/null +++ b/components/zep/actions/add-user/add-user.mjs @@ -0,0 +1,64 @@ +import zep from "../../zep.app.mjs"; +import utils from "../../common/utils.mjs"; + +export default { + key: "zep-add-user", + name: "Add User", + description: "Adds a user in Zep. [See the documentation](https://help.getzep.com/api-reference/user/add)", + version: "0.0.1", + type: "action", + props: { + zep, + userId: { + type: "string", + label: "User ID", + description: "The unique identifier of the new user", + }, + email: { + type: "string", + label: "Email", + description: "Email address of the user", + optional: true, + }, + firstName: { + type: "string", + label: "First Name", + description: "First name of the new user", + optional: true, + }, + lastName: { + type: "string", + label: "Last Name", + description: "Last name of the new user", + optional: true, + }, + factRatingInstructions: { + propDefinition: [ + zep, + "factRatingInstructions", + ], + }, + metadata: { + propDefinition: [ + zep, + "metadata", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.zep.createUser({ + $, + data: { + email: this.email, + first_name: this.firstName, + last_name: this.lastName, + fact_rating_instructions: utils.parseObject(this.factRatingInstructions), + metadata: utils.parseObject(this.metadata), + user_id: this.userId, + }, + }); + $.export("$summary", `Successfully added user with ID: ${response.id}`); + return response; + }, +}; diff --git a/components/zep/actions/create-session/create-session.mjs b/components/zep/actions/create-session/create-session.mjs new file mode 100644 index 0000000000000..3700067d25cbf --- /dev/null +++ b/components/zep/actions/create-session/create-session.mjs @@ -0,0 +1,50 @@ +import zep from "../../zep.app.mjs"; +import utils from "../../common/utils.mjs"; + +export default { + key: "zep-create-session", + name: "Create Session", + description: "Creates a new session in Zep. [See the documentation](https://help.getzep.com/api-reference/memory/add-session)", + version: "0.0.1", + type: "action", + props: { + zep, + sessionId: { + type: "string", + label: "Session ID", + description: "The unique identifier of the session", + }, + userId: { + propDefinition: [ + zep, + "userId", + ], + }, + factRatingInstructions: { + propDefinition: [ + zep, + "factRatingInstructions", + ], + }, + metadata: { + propDefinition: [ + zep, + "metadata", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.zep.createSession({ + $, + data: { + session_id: this.sessionId, + user_id: this.userId, + fact_rating_instructions: utils.parseObject(this.factRatingInstructions), + metadata: utils.parseObject(this.metadata), + }, + }); + $.export("$summary", `Created session with ID ${this.sessionId}`); + return response; + }, +}; diff --git a/components/zep/actions/update-session/update-session.mjs b/components/zep/actions/update-session/update-session.mjs new file mode 100644 index 0000000000000..093227a3de2dd --- /dev/null +++ b/components/zep/actions/update-session/update-session.mjs @@ -0,0 +1,44 @@ +import zep from "../../zep.app.mjs"; +import utils from "../../common/utils.mjs"; + +export default { + key: "zep-update-session", + name: "Update Session", + description: "Updates an existing session in Zep. [See the documentation](https://help.getzep.com/api-reference/memory/update-session)", + version: "0.0.1", + type: "action", + props: { + zep, + sessionId: { + propDefinition: [ + zep, + "sessionId", + ], + }, + metadata: { + propDefinition: [ + zep, + "metadata", + ], + description: "An object of key/value pairs representing the metadata to add to the session", + }, + factRatingInstructions: { + propDefinition: [ + zep, + "factRatingInstructions", + ], + }, + }, + async run({ $ }) { + const response = await this.zep.updateSession({ + $, + sessionId: this.sessionId, + data: { + fact_rating_instructions: utils.parseObject(this.factRatingInstructions), + metadata: utils.parseObject(this.metadata), + }, + }); + $.export("$summary", `Successfully updated ssession with ID ${this.sessionId}`); + return response; + }, +}; diff --git a/components/zep/common/utils.mjs b/components/zep/common/utils.mjs new file mode 100644 index 0000000000000..32476c3373b72 --- /dev/null +++ b/components/zep/common/utils.mjs @@ -0,0 +1,30 @@ +function parseObject(obj) { + if (!obj) { + return undefined; + } + + return typeof obj === "string" + ? JSON.parse(obj) + : obj; +} + +function parseArray(arr) { + if (!arr) { + return undefined; + } + + if (typeof arr === "string") { + return JSON.parse(arr); + } + + if (Array.isArray(arr)) { + return arr.map((item) => parseObject(item)); + } + + return arr; +} + +export default { + parseObject, + parseArray, +}; diff --git a/components/zep/package.json b/components/zep/package.json index ae467e60b94e9..5f49cb70ac437 100644 --- a/components/zep/package.json +++ b/components/zep/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/zep", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Zep Components", "main": "zep.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/zep/sources/common/base.mjs b/components/zep/sources/common/base.mjs new file mode 100644 index 0000000000000..d186ee9b3ee88 --- /dev/null +++ b/components/zep/sources/common/base.mjs @@ -0,0 +1,80 @@ +import zep from "../../zep.app.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; + +export default { + props: { + zep, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastTs() { + return this.db.get("lastTs") || 0; + }, + _setLastTs(lastTs) { + this.db.set("lastTs", lastTs); + }, + async processEvent(max) { + const lastTs = this._getLastTs(); + const results = await this.getNewResults(lastTs, max); + results.forEach((item) => this.emitEvent(item)); + }, + async getSessions({ + lastTs, orderBy, max, updateLastTs = true, + }) { + const params = { + page_size: max || 1000, + order_by: orderBy, + asc: false, + }; + + const { sessions: results } = await this.zep.listSessions({ + params, + }); + + const sessions = []; + for (const session of results) { + const ts = Date.parse(session[orderBy]); + if (ts >= lastTs) { + sessions.push(session); + } else { + break; + } + if (max && sessions.length >= max) { + break; + } + } + + if (!sessions.length) { + return []; + } + if (updateLastTs) { + this._setLastTs(Date.parse(sessions[0][orderBy])); + } + return sessions.reverse(); + }, + emitEvent(item) { + const meta = this.generateMeta(item); + this.$emit(item, meta); + }, + getNewResults() { + throw new Error("getNewResults is not implemented"); + }, + generateMeta() { + throw new Error("generateMeta is not implemented"); + }, + }, + hooks: { + async deploy() { + await this.processEvent(25); + }, + }, + async run() { + await this.processEvent(); + }, +}; diff --git a/components/zep/sources/new-message/new-message.mjs b/components/zep/sources/new-message/new-message.mjs new file mode 100644 index 0000000000000..72869259ea2ec --- /dev/null +++ b/components/zep/sources/new-message/new-message.mjs @@ -0,0 +1,80 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "zep-new-message", + name: "New Message in Session", + description: "Emit new event when a message is added to a session. [See the documentation](https://help.getzep.com/api-reference/memory/get-session-messages)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + async getNewResults(lastTs, max) { + const sessionIds = await this.getRecentlyUpdatedSessionIds(lastTs); + let messages = []; + let maxTs = lastTs; + + for (const sessionId of sessionIds) { + const results = this.paginateMessages(sessionId); + + for await (const message of results) { + const ts = Date.parse(message.created_at); + if (ts >= lastTs) { + messages.push({ + ...message, + session_id: sessionId, + }); + maxTs = Math.max(maxTs, ts); + } + } + } + + this._setLastTs(maxTs); + + // sort by created_at + messages = messages.sort((a, b) => Date.parse(a.created_at) - Date.parse(b.created_at)); + + if (max) { + messages = messages.slice(-1 * max); + } + + return messages; + }, + async getRecentlyUpdatedSessionIds(lastTs) { + const sessions = await this.getSessions({ + lastTs, + orderBy: "updated_at", + updateLastTs: false, + max: 100, + }); + return sessions?.map(({ session_id: id }) => id) || []; + }, + async *paginateMessages(sessionId) { + const params = { + limit: 1000, + cursor: 1, + }; + let total; + + do { + const { messages } = await this.zep.listMessages({ + sessionId, + params, + }); + for (const message of messages) { + yield message; + } + total = messages?.length; + params.cursor++; + } while (total); + }, + generateMeta(message) { + return { + id: message.uuid, + summary: `New Message: ${message.content}`, + ts: Date.parse(message.created_at), + }; + }, + }, +}; diff --git a/components/zep/sources/new-session/new-session.mjs b/components/zep/sources/new-session/new-session.mjs new file mode 100644 index 0000000000000..49842ba20f6bc --- /dev/null +++ b/components/zep/sources/new-session/new-session.mjs @@ -0,0 +1,28 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "zep-new-session", + name: "New Session Created", + description: "Emit new event when a new session is created in Zep. [See the documentation](https://help.getzep.com/api-reference/memory/list-sessions)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getNewResults(lastTs, max) { + return this.getSessions({ + lastTs, + max, + orderBy: "created_at", + }); + }, + generateMeta(session) { + return { + id: session.session_id, + summary: `New Session: ${session.session_id}`, + ts: Date.parse(session.created_at), + }; + }, + }, +}; diff --git a/components/zep/sources/session-updated/session-updated.mjs b/components/zep/sources/session-updated/session-updated.mjs new file mode 100644 index 0000000000000..08e7955f228b8 --- /dev/null +++ b/components/zep/sources/session-updated/session-updated.mjs @@ -0,0 +1,29 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "zep-session-updated", + name: "Session Updated", + description: "Emit new event when an existing session is updated. [See the documentation](https://help.getzep.com/api-reference/memory/list-sessions)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getNewResults(lastTs, max) { + return this.getSessions({ + lastTs, + max, + orderBy: "updated_at", + }); + }, + generateMeta(session) { + const ts = Date.parse(session.updated_at); + return { + id: `${session.session_id}${ts}`, + summary: `Updated Session: ${session.session_id}`, + ts, + }; + }, + }, +}; diff --git a/components/zep/zep.app.mjs b/components/zep/zep.app.mjs index c612cdfc19f64..4ea32d1fb7b45 100644 --- a/components/zep/zep.app.mjs +++ b/components/zep/zep.app.mjs @@ -1,11 +1,124 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "zep", - propDefinitions: {}, + propDefinitions: { + sessionId: { + type: "string", + label: "Session ID", + description: "The ID of the session", + async options({ page }) { + const { sessions } = await this.listSessions({ + params: { + page_number: page, + order_by: "updated_at", + asc: false, + }, + }); + return sessions?.map(({ session_id }) => session_id) || []; + }, + }, + userId: { + type: "string", + label: "User ID", + description: "The ID of the user", + async options({ page }) { + const { users } = await this.listUsers({ + params: { + pageNumber: page, + }, + }); + return users?.map(({ + user_id: value, first_name: firstName, last_name: lastName, email, + }) => ({ + value, + label: firstName || lastName + ? (`${firstName} ${lastName}`).trim() + : email || value, + })) || []; + }, + }, + factRatingInstructions: { + type: "object", + label: "Fact Rating Instructions", + description: "Instructions to use for the fact rating consisting of examples and instruction. Example: `{ \"examples\": { \"high\": \"high\", \"low\": \"low\", \"medium\": \"medium\" }, \"instruction\": \"instruction\" }`. [See the documentation](https://help.getzep.com/api-reference/memory/add-session) for more info.", + optional: true, + }, + metadata: { + type: "object", + label: "Metadata", + description: "An object of key/value pairs representing the metadata associated with the session", + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.getzep.com/api/v2"; + }, + _makeRequest({ + $ = this, + path, + ...otherOpts + }) { + return axios($, { + url: `${this._baseUrl()}${path}`, + headers: { + "authorization": `Api-Key ${this.$auth.api_key}`, + }, + ...otherOpts, + }); + }, + listSessions(opts = {}) { + return this._makeRequest({ + path: "/sessions-ordered", + ...opts, + }); + }, + listUsers(opts = {}) { + return this._makeRequest({ + path: "/users-ordered", + ...opts, + }); + }, + listMessages({ + sessionId, ...opts + }) { + return this._makeRequest({ + path: `/sessions/${sessionId}/messages`, + ...opts, + }); + }, + createSession(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/sessions", + ...opts, + }); + }, + createUser(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/users", + ...opts, + }); + }, + addMemoryToSession({ + sessionId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/sessions/${sessionId}/memory`, + ...opts, + }); + }, + updateSession({ + sessionId, ...opts + }) { + return this._makeRequest({ + method: "PATCH", + path: `/sessions/${sessionId}`, + ...opts, + }); }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b671a34370c6a..a4f61b6504d90 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14148,7 +14148,11 @@ importers: specifier: ^3.0.3 version: 3.0.3 - components/zep: {} + components/zep: + dependencies: + '@pipedream/platform': + specifier: ^3.0.3 + version: 3.0.3 components/zerobounce: dependencies: