opencode-database-plugin 1.0.8 → 1.0.10
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/db.d.ts +3 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +360 -249
- package/package.json +1 -1
package/dist/db.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import postgres from "postgres";
|
|
2
2
|
export declare const sql: postgres.Sql<{}>;
|
|
3
|
+
export declare function isDatabaseHealthy(): boolean;
|
|
3
4
|
export declare function ensureConnection(): Promise<boolean>;
|
|
5
|
+
export declare function safeQuery<T>(queryFn: () => Promise<T>, timeoutMs?: number): Promise<T | undefined>;
|
|
6
|
+
export declare function fireAndForget(queryFn: () => Promise<unknown>, onError?: (error: unknown) => void): void;
|
|
4
7
|
//# sourceMappingURL=db.d.ts.map
|
package/dist/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAWhC,eAAO,MAAM,GAAG,kBAMd,CAAC;AAOH,wBAAgB,iBAAiB,IAAI,OAAO,CAY3C;AAYD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAUzD;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,SAAS,GAAE,MAAsB,GAChC,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CA2BxB;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC/B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GACjC,IAAI,CAMN"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AA0E/D,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3C,CAAC;CACH;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE;YACL,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,GAAG,CAAC,EAAE,MAAM,CAAC;SACd,CAAC;KACH,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3C,CAAC;CACH;AAmBD,eAAO,MAAM,cAAc,EAAE,MAopB5B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1947,30 +1947,125 @@ function osUsername() {
|
|
|
1947
1947
|
|
|
1948
1948
|
// db.ts
|
|
1949
1949
|
var DATABASE_URL = process.env.OPENCODE_DATABASE_URL || "postgres://opencode:opencode@postgres:5432/opencode";
|
|
1950
|
+
var QUERY_TIMEOUT = parseInt(process.env.OPENCODE_DB_QUERY_TIMEOUT || "10000", 10);
|
|
1950
1951
|
var sql = src_default(DATABASE_URL, {
|
|
1951
1952
|
max: 10,
|
|
1952
|
-
idle_timeout:
|
|
1953
|
-
connect_timeout:
|
|
1953
|
+
idle_timeout: 30,
|
|
1954
|
+
connect_timeout: 10,
|
|
1955
|
+
max_lifetime: 60 * 30,
|
|
1954
1956
|
onnotice: () => {}
|
|
1955
1957
|
});
|
|
1958
|
+
var consecutiveFailures = 0;
|
|
1959
|
+
var lastFailureTime = 0;
|
|
1960
|
+
var MAX_BACKOFF_MS = 60000;
|
|
1961
|
+
var BASE_BACKOFF_MS = 1000;
|
|
1962
|
+
function isDatabaseHealthy() {
|
|
1963
|
+
if (consecutiveFailures === 0) {
|
|
1964
|
+
return true;
|
|
1965
|
+
}
|
|
1966
|
+
const backoffMs = Math.min(BASE_BACKOFF_MS * Math.pow(2, consecutiveFailures - 1), MAX_BACKOFF_MS);
|
|
1967
|
+
const timeSinceFailure = Date.now() - lastFailureTime;
|
|
1968
|
+
return timeSinceFailure >= backoffMs;
|
|
1969
|
+
}
|
|
1970
|
+
function markHealthy() {
|
|
1971
|
+
consecutiveFailures = 0;
|
|
1972
|
+
lastFailureTime = 0;
|
|
1973
|
+
}
|
|
1974
|
+
function markUnhealthy() {
|
|
1975
|
+
consecutiveFailures++;
|
|
1976
|
+
lastFailureTime = Date.now();
|
|
1977
|
+
}
|
|
1956
1978
|
async function ensureConnection() {
|
|
1957
1979
|
try {
|
|
1958
1980
|
await sql`SELECT 1`;
|
|
1981
|
+
markHealthy();
|
|
1959
1982
|
return true;
|
|
1960
1983
|
} catch (error) {
|
|
1961
1984
|
console.error("[database] Database connection failed:", error);
|
|
1985
|
+
markUnhealthy();
|
|
1962
1986
|
return false;
|
|
1963
1987
|
}
|
|
1964
1988
|
}
|
|
1989
|
+
async function safeQuery(queryFn, timeoutMs = QUERY_TIMEOUT) {
|
|
1990
|
+
if (!isDatabaseHealthy()) {
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1993
|
+
try {
|
|
1994
|
+
const result = await Promise.race([
|
|
1995
|
+
queryFn(),
|
|
1996
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Query timeout")), timeoutMs))
|
|
1997
|
+
]);
|
|
1998
|
+
markHealthy();
|
|
1999
|
+
return result;
|
|
2000
|
+
} catch (error) {
|
|
2001
|
+
if (error instanceof Error && (error.message.includes("connection") || error.message.includes("timeout") || error.message.includes("ECONNREFUSED") || error.message.includes("ENOTFOUND") || error.message.includes("ETIMEDOUT"))) {
|
|
2002
|
+
markUnhealthy();
|
|
2003
|
+
}
|
|
2004
|
+
throw error;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
function fireAndForget(queryFn, onError) {
|
|
2008
|
+
safeQuery(queryFn).catch((error) => {
|
|
2009
|
+
if (onError) {
|
|
2010
|
+
onError(error);
|
|
2011
|
+
}
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
1965
2014
|
|
|
1966
2015
|
// index.ts
|
|
2016
|
+
var STALE_ENTRY_TIMEOUT_MS = 15 * 60 * 1000;
|
|
2017
|
+
var CLEANUP_INTERVAL_MS = 60 * 1000;
|
|
1967
2018
|
var pendingExecutions = new Map;
|
|
1968
2019
|
var callIdToPartId = new Map;
|
|
1969
2020
|
var pendingUserMessages = new Map;
|
|
1970
2021
|
var tokensCountedBySession = new Map;
|
|
2022
|
+
var callIdTimestamps = new Map;
|
|
2023
|
+
function cleanupStaleMaps() {
|
|
2024
|
+
const now = Date.now();
|
|
2025
|
+
for (const [key, value] of pendingExecutions) {
|
|
2026
|
+
if (now - value.startedAt.getTime() > STALE_ENTRY_TIMEOUT_MS) {
|
|
2027
|
+
pendingExecutions.delete(key);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
for (const [key, value] of pendingUserMessages) {
|
|
2031
|
+
if (now - value.timestamp > STALE_ENTRY_TIMEOUT_MS) {
|
|
2032
|
+
pendingUserMessages.delete(key);
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
for (const [key, timestamp] of callIdTimestamps) {
|
|
2036
|
+
if (now - timestamp > STALE_ENTRY_TIMEOUT_MS) {
|
|
2037
|
+
callIdToPartId.delete(key);
|
|
2038
|
+
callIdTimestamps.delete(key);
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
for (const [sessionId, messageTimestamps] of tokensCountedBySession) {
|
|
2042
|
+
for (const [messageId, timestamp] of messageTimestamps) {
|
|
2043
|
+
if (now - timestamp > STALE_ENTRY_TIMEOUT_MS) {
|
|
2044
|
+
messageTimestamps.delete(messageId);
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
if (messageTimestamps.size === 0) {
|
|
2048
|
+
tokensCountedBySession.delete(sessionId);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
var cleanupInterval = setInterval(cleanupStaleMaps, CLEANUP_INTERVAL_MS);
|
|
2053
|
+
if (cleanupInterval.unref) {
|
|
2054
|
+
cleanupInterval.unref();
|
|
2055
|
+
}
|
|
1971
2056
|
function generateCorrelationId() {
|
|
1972
2057
|
return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
1973
2058
|
}
|
|
2059
|
+
function logError(client, message, extra) {
|
|
2060
|
+
Promise.resolve(client.app.log({
|
|
2061
|
+
body: {
|
|
2062
|
+
service: "database",
|
|
2063
|
+
level: "error",
|
|
2064
|
+
message,
|
|
2065
|
+
extra
|
|
2066
|
+
}
|
|
2067
|
+
})).catch(() => {});
|
|
2068
|
+
}
|
|
1974
2069
|
var DatabasePlugin = async ({ client }) => {
|
|
1975
2070
|
const connected = await ensureConnection();
|
|
1976
2071
|
if (!connected) {
|
|
@@ -1990,7 +2085,7 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
1990
2085
|
switch (event.type) {
|
|
1991
2086
|
case "session.created": {
|
|
1992
2087
|
const info = props.info;
|
|
1993
|
-
|
|
2088
|
+
fireAndForget(() => sql`
|
|
1994
2089
|
INSERT INTO sessions (id, title, parent_id, project_id, directory, status, created_at)
|
|
1995
2090
|
VALUES (
|
|
1996
2091
|
${info.id},
|
|
@@ -2006,43 +2101,52 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2006
2101
|
parent_id = COALESCE(${info.parentID || null}, sessions.parent_id),
|
|
2007
2102
|
project_id = COALESCE(${info.projectID || null}, sessions.project_id),
|
|
2008
2103
|
directory = COALESCE(${info.directory || null}, sessions.directory)
|
|
2009
|
-
|
|
2104
|
+
`, (error) => logError(client, "Error in session.created", {
|
|
2105
|
+
error: String(error)
|
|
2106
|
+
}));
|
|
2010
2107
|
break;
|
|
2011
2108
|
}
|
|
2012
2109
|
case "session.updated": {
|
|
2013
2110
|
const info = props.info;
|
|
2014
|
-
|
|
2111
|
+
fireAndForget(() => sql`
|
|
2015
2112
|
UPDATE sessions
|
|
2016
2113
|
SET title = COALESCE(${info.title || null}, title),
|
|
2017
2114
|
share_url = COALESCE(${info.share?.url || null}, share_url)
|
|
2018
2115
|
WHERE id = ${info.id}
|
|
2019
|
-
|
|
2116
|
+
`, (error) => logError(client, "Error in session.updated", {
|
|
2117
|
+
error: String(error)
|
|
2118
|
+
}));
|
|
2020
2119
|
break;
|
|
2021
2120
|
}
|
|
2022
2121
|
case "session.deleted": {
|
|
2023
2122
|
const info = props.info;
|
|
2024
|
-
|
|
2123
|
+
fireAndForget(() => sql`
|
|
2025
2124
|
UPDATE sessions
|
|
2026
2125
|
SET deleted_at = NOW(), status = 'deleted'
|
|
2027
2126
|
WHERE id = ${info.id}
|
|
2028
|
-
|
|
2127
|
+
`, (error) => logError(client, "Error in session.deleted", {
|
|
2128
|
+
error: String(error)
|
|
2129
|
+
}));
|
|
2029
2130
|
tokensCountedBySession.delete(info.id);
|
|
2030
2131
|
break;
|
|
2031
2132
|
}
|
|
2032
2133
|
case "session.idle": {
|
|
2033
2134
|
const sessionID = props.sessionID;
|
|
2034
|
-
|
|
2135
|
+
fireAndForget(() => sql`
|
|
2035
2136
|
UPDATE sessions
|
|
2036
2137
|
SET status = 'idle', updated_at = NOW()
|
|
2037
2138
|
WHERE id = ${sessionID}
|
|
2038
|
-
|
|
2139
|
+
`, (error) => logError(client, "Error in session.idle", {
|
|
2140
|
+
error: String(error)
|
|
2141
|
+
}));
|
|
2039
2142
|
break;
|
|
2040
2143
|
}
|
|
2041
2144
|
case "session.error": {
|
|
2042
2145
|
const sessionID = props.sessionID;
|
|
2043
2146
|
const error = props.error;
|
|
2044
2147
|
if (sessionID) {
|
|
2045
|
-
|
|
2148
|
+
fireAndForget(async () => {
|
|
2149
|
+
await sql`
|
|
2046
2150
|
INSERT INTO session_errors (session_id, error_type, error_message, error_data)
|
|
2047
2151
|
VALUES (
|
|
2048
2152
|
${sessionID},
|
|
@@ -2051,70 +2155,61 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2051
2155
|
${error ? sql.json(error) : null}
|
|
2052
2156
|
)
|
|
2053
2157
|
`;
|
|
2054
|
-
|
|
2158
|
+
await sql`
|
|
2055
2159
|
UPDATE sessions SET status = 'error' WHERE id = ${sessionID}
|
|
2056
2160
|
`;
|
|
2057
|
-
await client.app.log({
|
|
2058
|
-
body: {
|
|
2059
|
-
service: "database",
|
|
2060
|
-
level: "info",
|
|
2061
|
-
message: "Session error",
|
|
2062
|
-
extra: { sessionID, errorMessage: error?.data?.message }
|
|
2063
|
-
}
|
|
2064
2161
|
});
|
|
2065
2162
|
}
|
|
2066
2163
|
break;
|
|
2067
2164
|
}
|
|
2068
2165
|
case "session.compacted": {
|
|
2069
2166
|
const sessionID = props.sessionID;
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2167
|
+
try {
|
|
2168
|
+
const result = await safeQuery(() => sql`
|
|
2169
|
+
SELECT context_tokens, input_tokens, output_tokens,
|
|
2170
|
+
cache_read_tokens, cache_write_tokens, reasoning_tokens, estimated_cost
|
|
2171
|
+
FROM sessions WHERE id = ${sessionID}
|
|
2172
|
+
`);
|
|
2173
|
+
const sessionState = result?.[0];
|
|
2174
|
+
if (sessionState) {
|
|
2175
|
+
fireAndForget(() => sql`
|
|
2176
|
+
INSERT INTO compactions (
|
|
2177
|
+
session_id,
|
|
2178
|
+
context_tokens_before,
|
|
2179
|
+
cumulative_input_tokens,
|
|
2180
|
+
cumulative_output_tokens,
|
|
2181
|
+
cumulative_cache_read,
|
|
2182
|
+
cumulative_cache_write,
|
|
2183
|
+
cumulative_reasoning,
|
|
2184
|
+
cumulative_cost
|
|
2185
|
+
)
|
|
2186
|
+
VALUES (
|
|
2187
|
+
${sessionID},
|
|
2188
|
+
${sessionState.context_tokens || 0},
|
|
2189
|
+
${sessionState.input_tokens || 0},
|
|
2190
|
+
${sessionState.output_tokens || 0},
|
|
2191
|
+
${sessionState.cache_read_tokens || 0},
|
|
2192
|
+
${sessionState.cache_write_tokens || 0},
|
|
2193
|
+
${sessionState.reasoning_tokens || 0},
|
|
2194
|
+
${parseFloat(sessionState.estimated_cost || "0")}
|
|
2195
|
+
)
|
|
2196
|
+
`);
|
|
2197
|
+
}
|
|
2198
|
+
fireAndForget(() => sql`
|
|
2199
|
+
UPDATE sessions
|
|
2200
|
+
SET
|
|
2201
|
+
status = 'compacted',
|
|
2202
|
+
peak_context_tokens = GREATEST(peak_context_tokens, context_tokens),
|
|
2203
|
+
context_tokens = 0,
|
|
2204
|
+
compaction_count = compaction_count + 1
|
|
2205
|
+
WHERE id = ${sessionID}
|
|
2206
|
+
`);
|
|
2207
|
+
} catch {}
|
|
2108
2208
|
tokensCountedBySession.delete(sessionID);
|
|
2109
2209
|
break;
|
|
2110
2210
|
}
|
|
2111
2211
|
case "message.updated": {
|
|
2112
2212
|
const info = props.info;
|
|
2113
|
-
await sql`
|
|
2114
|
-
INSERT INTO sessions (id, status, created_at, updated_at)
|
|
2115
|
-
VALUES (${info.sessionID}, 'active', NOW(), NOW())
|
|
2116
|
-
ON CONFLICT (id) DO UPDATE SET updated_at = NOW()
|
|
2117
|
-
`;
|
|
2118
2213
|
let messageContent = info.parts;
|
|
2119
2214
|
let textContent = null;
|
|
2120
2215
|
let systemPrompt = info.system || null;
|
|
@@ -2134,30 +2229,39 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2134
2229
|
}
|
|
2135
2230
|
const modelProvider = info.providerID || info.model?.providerID || null;
|
|
2136
2231
|
const modelId = info.modelID || info.model?.modelID || null;
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2232
|
+
fireAndForget(async () => {
|
|
2233
|
+
await sql`
|
|
2234
|
+
INSERT INTO sessions (id, status, created_at, updated_at)
|
|
2235
|
+
VALUES (${info.sessionID}, 'active', NOW(), NOW())
|
|
2236
|
+
ON CONFLICT (id) DO UPDATE SET updated_at = NOW()
|
|
2237
|
+
`;
|
|
2238
|
+
await sql`
|
|
2239
|
+
INSERT INTO messages (id, session_id, role, model_provider, model_id, text, summary, content, system_prompt, created_at)
|
|
2240
|
+
VALUES (
|
|
2241
|
+
${info.id},
|
|
2242
|
+
${info.sessionID},
|
|
2243
|
+
${info.role},
|
|
2244
|
+
${modelProvider},
|
|
2245
|
+
${modelId},
|
|
2246
|
+
${textContent},
|
|
2247
|
+
${info.summary?.title || null},
|
|
2248
|
+
${messageContent ? sql.json(messageContent) : null},
|
|
2249
|
+
${systemPrompt},
|
|
2250
|
+
NOW()
|
|
2251
|
+
)
|
|
2252
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
2253
|
+
role = ${info.role},
|
|
2254
|
+
model_provider = COALESCE(EXCLUDED.model_provider, messages.model_provider),
|
|
2255
|
+
model_id = COALESCE(EXCLUDED.model_id, messages.model_id),
|
|
2256
|
+
text = COALESCE(${textContent}, messages.text),
|
|
2257
|
+
summary = COALESCE(${info.summary?.title || null}, messages.summary),
|
|
2258
|
+
content = COALESCE(${messageContent ? sql.json(messageContent) : null}, messages.content),
|
|
2259
|
+
system_prompt = COALESCE(${systemPrompt}, messages.system_prompt)
|
|
2260
|
+
`;
|
|
2261
|
+
}, (error) => logError(client, "Error in message.updated", {
|
|
2262
|
+
error: String(error)
|
|
2263
|
+
}));
|
|
2264
|
+
const sessionTokens = tokensCountedBySession.get(info.sessionID) || new Map;
|
|
2161
2265
|
if (info.role === "assistant" && info.tokens && !sessionTokens.has(info.id)) {
|
|
2162
2266
|
const inputTokens = info.tokens.input ?? 0;
|
|
2163
2267
|
const outputTokens = info.tokens.output ?? 0;
|
|
@@ -2165,10 +2269,10 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2165
2269
|
const cacheRead = info.tokens.cache?.read ?? 0;
|
|
2166
2270
|
const cacheWrite = info.tokens.cache?.write ?? 0;
|
|
2167
2271
|
if (inputTokens > 0 || outputTokens > 0) {
|
|
2168
|
-
sessionTokens.
|
|
2272
|
+
sessionTokens.set(info.id, Date.now());
|
|
2169
2273
|
tokensCountedBySession.set(info.sessionID, sessionTokens);
|
|
2170
2274
|
const contextSize = inputTokens + cacheRead;
|
|
2171
|
-
|
|
2275
|
+
fireAndForget(() => sql`
|
|
2172
2276
|
UPDATE sessions
|
|
2173
2277
|
SET
|
|
2174
2278
|
input_tokens = input_tokens + ${inputTokens},
|
|
@@ -2181,16 +2285,18 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2181
2285
|
model_provider = COALESCE(${modelProvider}, model_provider),
|
|
2182
2286
|
model_id = COALESCE(${modelId}, model_id)
|
|
2183
2287
|
WHERE id = ${info.sessionID}
|
|
2184
|
-
|
|
2288
|
+
`, (error) => logError(client, "Error updating session tokens", {
|
|
2289
|
+
error: String(error)
|
|
2290
|
+
}));
|
|
2185
2291
|
}
|
|
2186
2292
|
}
|
|
2187
2293
|
break;
|
|
2188
2294
|
}
|
|
2189
2295
|
case "message.removed": {
|
|
2190
2296
|
const messageID = props.messageID;
|
|
2191
|
-
|
|
2297
|
+
fireAndForget(() => sql`
|
|
2192
2298
|
DELETE FROM messages WHERE id = ${messageID}
|
|
2193
|
-
|
|
2299
|
+
`);
|
|
2194
2300
|
break;
|
|
2195
2301
|
}
|
|
2196
2302
|
case "message.part.updated": {
|
|
@@ -2199,56 +2305,60 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2199
2305
|
const textContent = part.text || null;
|
|
2200
2306
|
if (part.type === "tool" && part.callID) {
|
|
2201
2307
|
callIdToPartId.set(part.callID, part.id);
|
|
2308
|
+
callIdTimestamps.set(part.callID, Date.now());
|
|
2202
2309
|
const pending = pendingExecutions.get(part.callID);
|
|
2203
2310
|
if (pending) {
|
|
2204
2311
|
pending.partId = part.id;
|
|
2205
2312
|
}
|
|
2206
2313
|
}
|
|
2207
2314
|
if (part.type === "step-finish" && part.cost !== undefined) {
|
|
2208
|
-
|
|
2315
|
+
const cost = part.cost;
|
|
2316
|
+
fireAndForget(() => sql`
|
|
2209
2317
|
UPDATE sessions
|
|
2210
|
-
SET estimated_cost = estimated_cost + ${
|
|
2318
|
+
SET estimated_cost = estimated_cost + ${cost}
|
|
2211
2319
|
WHERE id = ${part.sessionID}
|
|
2212
|
-
|
|
2320
|
+
`);
|
|
2213
2321
|
}
|
|
2214
|
-
await sql`
|
|
2215
|
-
INSERT INTO messages (id, session_id, role, created_at)
|
|
2216
|
-
VALUES (${part.messageID}, ${part.sessionID}, 'assistant', NOW())
|
|
2217
|
-
ON CONFLICT (id) DO UPDATE SET
|
|
2218
|
-
role = COALESCE(messages.role, 'assistant')
|
|
2219
|
-
`;
|
|
2220
|
-
await sql`
|
|
2221
|
-
INSERT INTO sessions (id, status, created_at)
|
|
2222
|
-
VALUES (${part.sessionID}, 'active', NOW())
|
|
2223
|
-
ON CONFLICT (id) DO NOTHING
|
|
2224
|
-
`;
|
|
2225
2322
|
const isStreamingTextPart = part.type === "text" || part.type === "reasoning";
|
|
2226
2323
|
const partAsJson = { ...part };
|
|
2227
2324
|
if (isStreamingTextPart) {
|
|
2228
|
-
|
|
2229
|
-
INSERT INTO message_parts (id, message_id, part_type, tool_name, text, content, created_at)
|
|
2230
|
-
VALUES (
|
|
2231
|
-
${part.id},
|
|
2232
|
-
${part.messageID},
|
|
2233
|
-
${part.type},
|
|
2234
|
-
${toolName},
|
|
2235
|
-
${textContent},
|
|
2236
|
-
${sql.json(partAsJson)},
|
|
2237
|
-
NOW()
|
|
2238
|
-
)
|
|
2239
|
-
ON CONFLICT (id) DO NOTHING
|
|
2240
|
-
`;
|
|
2241
|
-
if (textContent) {
|
|
2325
|
+
fireAndForget(async () => {
|
|
2242
2326
|
await sql`
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
text = ${textContent},
|
|
2247
|
-
content = ${sql.json(partAsJson)}
|
|
2248
|
-
WHERE id = ${part.id}
|
|
2249
|
-
AND (text IS NULL OR LENGTH(text) < LENGTH(${textContent}))
|
|
2327
|
+
INSERT INTO sessions (id, status, created_at)
|
|
2328
|
+
VALUES (${part.sessionID}, 'active', NOW())
|
|
2329
|
+
ON CONFLICT (id) DO NOTHING
|
|
2250
2330
|
`;
|
|
2251
|
-
|
|
2331
|
+
await sql`
|
|
2332
|
+
INSERT INTO messages (id, session_id, role, created_at)
|
|
2333
|
+
VALUES (${part.messageID}, ${part.sessionID}, 'assistant', NOW())
|
|
2334
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
2335
|
+
role = COALESCE(messages.role, 'assistant')
|
|
2336
|
+
`;
|
|
2337
|
+
await sql`
|
|
2338
|
+
INSERT INTO message_parts (id, message_id, part_type, tool_name, text, content, created_at)
|
|
2339
|
+
VALUES (
|
|
2340
|
+
${part.id},
|
|
2341
|
+
${part.messageID},
|
|
2342
|
+
${part.type},
|
|
2343
|
+
${toolName},
|
|
2344
|
+
${textContent},
|
|
2345
|
+
${sql.json(partAsJson)},
|
|
2346
|
+
NOW()
|
|
2347
|
+
)
|
|
2348
|
+
ON CONFLICT (id) DO NOTHING
|
|
2349
|
+
`;
|
|
2350
|
+
if (textContent) {
|
|
2351
|
+
await sql`
|
|
2352
|
+
UPDATE message_parts
|
|
2353
|
+
SET
|
|
2354
|
+
tool_name = COALESCE(${toolName}, tool_name),
|
|
2355
|
+
text = ${textContent},
|
|
2356
|
+
content = ${sql.json(partAsJson)}
|
|
2357
|
+
WHERE id = ${part.id}
|
|
2358
|
+
AND (text IS NULL OR LENGTH(text) < LENGTH(${textContent}))
|
|
2359
|
+
`;
|
|
2360
|
+
}
|
|
2361
|
+
});
|
|
2252
2362
|
} else {
|
|
2253
2363
|
const statusPriority = {
|
|
2254
2364
|
pending: 1,
|
|
@@ -2258,59 +2368,72 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2258
2368
|
};
|
|
2259
2369
|
const currentStatus = part.state?.status || "pending";
|
|
2260
2370
|
const currentPriority = statusPriority[currentStatus] || 0;
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
${part.
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
${
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
WHEN 'pending' THEN 1
|
|
2284
|
-
WHEN 'running' THEN 2
|
|
2285
|
-
WHEN 'completed' THEN 3
|
|
2286
|
-
WHEN 'error' THEN 3
|
|
2287
|
-
ELSE 0
|
|
2288
|
-
END, 0
|
|
2371
|
+
fireAndForget(async () => {
|
|
2372
|
+
await sql`
|
|
2373
|
+
INSERT INTO sessions (id, status, created_at)
|
|
2374
|
+
VALUES (${part.sessionID}, 'active', NOW())
|
|
2375
|
+
ON CONFLICT (id) DO NOTHING
|
|
2376
|
+
`;
|
|
2377
|
+
await sql`
|
|
2378
|
+
INSERT INTO messages (id, session_id, role, created_at)
|
|
2379
|
+
VALUES (${part.messageID}, ${part.sessionID}, 'assistant', NOW())
|
|
2380
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
2381
|
+
role = COALESCE(messages.role, 'assistant')
|
|
2382
|
+
`;
|
|
2383
|
+
await sql`
|
|
2384
|
+
INSERT INTO message_parts (id, message_id, part_type, tool_name, text, content, created_at)
|
|
2385
|
+
VALUES (
|
|
2386
|
+
${part.id},
|
|
2387
|
+
${part.messageID},
|
|
2388
|
+
${part.type},
|
|
2389
|
+
${toolName},
|
|
2390
|
+
${textContent},
|
|
2391
|
+
${sql.json(partAsJson)},
|
|
2392
|
+
NOW()
|
|
2289
2393
|
)
|
|
2290
|
-
|
|
2394
|
+
ON CONFLICT (id) DO NOTHING
|
|
2395
|
+
`;
|
|
2396
|
+
await sql`
|
|
2397
|
+
UPDATE message_parts
|
|
2398
|
+
SET
|
|
2399
|
+
tool_name = COALESCE(${toolName}, tool_name),
|
|
2400
|
+
text = COALESCE(${textContent}, text),
|
|
2401
|
+
content = ${sql.json(partAsJson)}
|
|
2402
|
+
WHERE id = ${part.id}
|
|
2403
|
+
AND ${currentPriority} >= COALESCE(
|
|
2404
|
+
CASE (content->'state'->>'status')
|
|
2405
|
+
WHEN 'pending' THEN 1
|
|
2406
|
+
WHEN 'running' THEN 2
|
|
2407
|
+
WHEN 'completed' THEN 3
|
|
2408
|
+
WHEN 'error' THEN 3
|
|
2409
|
+
ELSE 0
|
|
2410
|
+
END, 0
|
|
2411
|
+
)
|
|
2412
|
+
`;
|
|
2413
|
+
});
|
|
2291
2414
|
}
|
|
2292
2415
|
if (part.type === "text" && textContent) {
|
|
2293
|
-
|
|
2416
|
+
fireAndForget(() => sql`
|
|
2294
2417
|
UPDATE messages
|
|
2295
2418
|
SET text = ${textContent}
|
|
2296
2419
|
WHERE id = ${part.messageID}
|
|
2297
2420
|
AND (text IS NULL OR LENGTH(text) < LENGTH(${textContent}))
|
|
2298
|
-
|
|
2421
|
+
`);
|
|
2299
2422
|
}
|
|
2300
2423
|
break;
|
|
2301
2424
|
}
|
|
2302
2425
|
case "message.part.removed": {
|
|
2303
2426
|
const partID = props.partID;
|
|
2304
|
-
|
|
2427
|
+
fireAndForget(() => sql`
|
|
2305
2428
|
DELETE FROM message_parts WHERE id = ${partID}
|
|
2306
|
-
|
|
2429
|
+
`);
|
|
2307
2430
|
break;
|
|
2308
2431
|
}
|
|
2309
2432
|
case "command.executed": {
|
|
2310
2433
|
const name = props.name;
|
|
2311
2434
|
const sessionID = props.sessionID;
|
|
2312
2435
|
const args = props.arguments;
|
|
2313
|
-
|
|
2436
|
+
fireAndForget(() => sql`
|
|
2314
2437
|
INSERT INTO commands (session_id, command_name, command_args, created_at)
|
|
2315
2438
|
VALUES (
|
|
2316
2439
|
${sessionID},
|
|
@@ -2318,27 +2441,23 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2318
2441
|
${args || null},
|
|
2319
2442
|
NOW()
|
|
2320
2443
|
)
|
|
2321
|
-
|
|
2444
|
+
`);
|
|
2322
2445
|
break;
|
|
2323
2446
|
}
|
|
2324
2447
|
}
|
|
2325
2448
|
} catch (error) {
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
level: "error",
|
|
2330
|
-
message: "Error recording event",
|
|
2331
|
-
extra: { eventType: event.type, error: String(error) }
|
|
2332
|
-
}
|
|
2449
|
+
logError(client, "Error recording event", {
|
|
2450
|
+
eventType: event.type,
|
|
2451
|
+
error: String(error)
|
|
2333
2452
|
});
|
|
2334
2453
|
}
|
|
2335
2454
|
},
|
|
2336
2455
|
"chat.message": async (input, output) => {
|
|
2337
2456
|
try {
|
|
2338
|
-
|
|
2457
|
+
fireAndForget(() => sql`
|
|
2339
2458
|
UPDATE sessions SET status = 'active', updated_at = NOW()
|
|
2340
2459
|
WHERE id = ${input.sessionID}
|
|
2341
|
-
|
|
2460
|
+
`);
|
|
2342
2461
|
const systemPrompt = output.message?.system;
|
|
2343
2462
|
if (output.parts && output.parts.length > 0) {
|
|
2344
2463
|
pendingUserMessages.set(input.sessionID, {
|
|
@@ -2354,14 +2473,7 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2354
2473
|
});
|
|
2355
2474
|
}
|
|
2356
2475
|
} catch (error) {
|
|
2357
|
-
|
|
2358
|
-
body: {
|
|
2359
|
-
service: "database",
|
|
2360
|
-
level: "error",
|
|
2361
|
-
message: "Error in chat.message",
|
|
2362
|
-
extra: { error: String(error) }
|
|
2363
|
-
}
|
|
2364
|
-
});
|
|
2476
|
+
logError(client, "Error in chat.message", { error: String(error) });
|
|
2365
2477
|
}
|
|
2366
2478
|
},
|
|
2367
2479
|
"tool.execute.before": async (input, output) => {
|
|
@@ -2375,7 +2487,7 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2375
2487
|
args: output.args || {},
|
|
2376
2488
|
startedAt
|
|
2377
2489
|
});
|
|
2378
|
-
|
|
2490
|
+
fireAndForget(() => sql`
|
|
2379
2491
|
INSERT INTO tool_executions (
|
|
2380
2492
|
correlation_id,
|
|
2381
2493
|
session_id,
|
|
@@ -2392,15 +2504,12 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2392
2504
|
${startedAt},
|
|
2393
2505
|
NOW()
|
|
2394
2506
|
)
|
|
2395
|
-
|
|
2507
|
+
`, (error) => logError(client, "Error recording tool start", {
|
|
2508
|
+
error: String(error)
|
|
2509
|
+
}));
|
|
2396
2510
|
} catch (error) {
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
service: "database",
|
|
2400
|
-
level: "error",
|
|
2401
|
-
message: "Error recording tool start",
|
|
2402
|
-
extra: { error: String(error) }
|
|
2403
|
-
}
|
|
2511
|
+
logError(client, "Error in tool.execute.before", {
|
|
2512
|
+
error: String(error)
|
|
2404
2513
|
});
|
|
2405
2514
|
}
|
|
2406
2515
|
},
|
|
@@ -2408,79 +2517,81 @@ var DatabasePlugin = async ({ client }) => {
|
|
|
2408
2517
|
try {
|
|
2409
2518
|
const completedAt = new Date;
|
|
2410
2519
|
const pending = pendingExecutions.get(input.callID);
|
|
2520
|
+
const partId = pending?.partId || callIdToPartId.get(input.callID) || null;
|
|
2411
2521
|
if (pending) {
|
|
2412
2522
|
const durationMs = completedAt.getTime() - pending.startedAt.getTime();
|
|
2413
|
-
|
|
2414
|
-
UPDATE tool_executions
|
|
2415
|
-
SET
|
|
2416
|
-
result = ${output.output ?? null},
|
|
2417
|
-
completed_at = ${completedAt},
|
|
2418
|
-
duration_ms = ${durationMs},
|
|
2419
|
-
success = true
|
|
2420
|
-
WHERE correlation_id = ${pending.correlationId}
|
|
2421
|
-
`;
|
|
2422
|
-
const partId = pending.partId || callIdToPartId.get(input.callID);
|
|
2423
|
-
if (partId && output.output) {
|
|
2424
|
-
const outputJson = JSON.stringify(output.output);
|
|
2523
|
+
fireAndForget(async () => {
|
|
2425
2524
|
await sql`
|
|
2426
|
-
UPDATE
|
|
2427
|
-
SET
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
${
|
|
2431
|
-
|
|
2432
|
-
WHERE
|
|
2433
|
-
AND (content->'state'->>'output') IS NULL
|
|
2525
|
+
UPDATE tool_executions
|
|
2526
|
+
SET
|
|
2527
|
+
result = ${output.output ?? null},
|
|
2528
|
+
completed_at = ${completedAt},
|
|
2529
|
+
duration_ms = ${durationMs},
|
|
2530
|
+
success = true
|
|
2531
|
+
WHERE correlation_id = ${pending.correlationId}
|
|
2434
2532
|
`;
|
|
2435
|
-
|
|
2533
|
+
if (partId && output.output) {
|
|
2534
|
+
const outputJson = JSON.stringify(output.output);
|
|
2535
|
+
await sql`
|
|
2536
|
+
UPDATE message_parts
|
|
2537
|
+
SET content = jsonb_set(
|
|
2538
|
+
COALESCE(content, '{"state":{}}'::jsonb),
|
|
2539
|
+
'{state,output}',
|
|
2540
|
+
${outputJson}::jsonb
|
|
2541
|
+
)
|
|
2542
|
+
WHERE id = ${partId}
|
|
2543
|
+
AND (content->'state'->>'output') IS NULL
|
|
2544
|
+
`;
|
|
2545
|
+
}
|
|
2546
|
+
});
|
|
2436
2547
|
pendingExecutions.delete(input.callID);
|
|
2437
2548
|
} else {
|
|
2438
|
-
|
|
2439
|
-
INSERT INTO tool_executions (
|
|
2440
|
-
correlation_id,
|
|
2441
|
-
session_id,
|
|
2442
|
-
tool_name,
|
|
2443
|
-
args,
|
|
2444
|
-
result,
|
|
2445
|
-
completed_at,
|
|
2446
|
-
success,
|
|
2447
|
-
created_at
|
|
2448
|
-
)
|
|
2449
|
-
VALUES (
|
|
2450
|
-
${generateCorrelationId()},
|
|
2451
|
-
${input.sessionID},
|
|
2452
|
-
${input.tool},
|
|
2453
|
-
${output.metadata ?? null},
|
|
2454
|
-
${output.output ?? null},
|
|
2455
|
-
${completedAt},
|
|
2456
|
-
true,
|
|
2457
|
-
NOW()
|
|
2458
|
-
)
|
|
2459
|
-
`;
|
|
2460
|
-
const partId = callIdToPartId.get(input.callID);
|
|
2461
|
-
if (partId && output.output) {
|
|
2462
|
-
const outputJson = JSON.stringify(output.output);
|
|
2549
|
+
fireAndForget(async () => {
|
|
2463
2550
|
await sql`
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2551
|
+
INSERT INTO tool_executions (
|
|
2552
|
+
correlation_id,
|
|
2553
|
+
session_id,
|
|
2554
|
+
tool_name,
|
|
2555
|
+
args,
|
|
2556
|
+
result,
|
|
2557
|
+
completed_at,
|
|
2558
|
+
success,
|
|
2559
|
+
created_at
|
|
2560
|
+
)
|
|
2561
|
+
VALUES (
|
|
2562
|
+
${generateCorrelationId()},
|
|
2563
|
+
${input.sessionID},
|
|
2564
|
+
${input.tool},
|
|
2565
|
+
${output.metadata ?? null},
|
|
2566
|
+
${output.output ?? null},
|
|
2567
|
+
${completedAt},
|
|
2568
|
+
true,
|
|
2569
|
+
NOW()
|
|
2469
2570
|
)
|
|
2470
|
-
WHERE id = ${partId}
|
|
2471
|
-
AND (content->'state'->>'output') IS NULL
|
|
2472
2571
|
`;
|
|
2473
|
-
|
|
2572
|
+
if (partId && output.output) {
|
|
2573
|
+
const outputJson = JSON.stringify(output.output);
|
|
2574
|
+
await sql`
|
|
2575
|
+
UPDATE message_parts
|
|
2576
|
+
SET content = jsonb_set(
|
|
2577
|
+
COALESCE(content, '{"state":{}}'::jsonb),
|
|
2578
|
+
'{state,output}',
|
|
2579
|
+
${outputJson}::jsonb
|
|
2580
|
+
)
|
|
2581
|
+
WHERE id = ${partId}
|
|
2582
|
+
AND (content->'state'->>'output') IS NULL
|
|
2583
|
+
`;
|
|
2584
|
+
}
|
|
2585
|
+
});
|
|
2474
2586
|
}
|
|
2475
2587
|
callIdToPartId.delete(input.callID);
|
|
2588
|
+
callIdTimestamps.delete(input.callID);
|
|
2476
2589
|
} catch (error) {
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
extra: { error: String(error) }
|
|
2483
|
-
}
|
|
2590
|
+
pendingExecutions.delete(input.callID);
|
|
2591
|
+
callIdToPartId.delete(input.callID);
|
|
2592
|
+
callIdTimestamps.delete(input.callID);
|
|
2593
|
+
logError(client, "Error recording tool completion", {
|
|
2594
|
+
error: String(error)
|
|
2484
2595
|
});
|
|
2485
2596
|
}
|
|
2486
2597
|
}
|
package/package.json
CHANGED