@grackle-ai/server 0.67.0 → 0.68.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/adapter-manager.d.ts +6 -2
- package/dist/adapter-manager.d.ts.map +1 -1
- package/dist/adapter-manager.js +15 -2
- package/dist/adapter-manager.js.map +1 -1
- package/dist/auto-reconnect.d.ts +16 -0
- package/dist/auto-reconnect.d.ts.map +1 -0
- package/dist/auto-reconnect.js +154 -0
- package/dist/auto-reconnect.js.map +1 -0
- package/dist/grpc-service.d.ts.map +1 -1
- package/dist/grpc-service.js +111 -0
- package/dist/grpc-service.js.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/knowledge-init.d.ts +3 -0
- package/dist/knowledge-init.d.ts.map +1 -1
- package/dist/knowledge-init.js +81 -7
- package/dist/knowledge-init.js.map +1 -1
- package/dist/ws-bridge.d.ts.map +1 -1
- package/dist/ws-bridge.js +4 -0
- package/dist/ws-bridge.js.map +1 -1
- package/package.json +7 -7
|
@@ -11,8 +11,12 @@ export declare function getConnection(environmentId: string): PowerLineConnectio
|
|
|
11
11
|
export declare function removeConnection(environmentId: string): void;
|
|
12
12
|
/** Return the map of all active environment connections. */
|
|
13
13
|
export declare function listConnections(): Map<string, PowerLineConnection>;
|
|
14
|
-
/**
|
|
15
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Start a periodic health-check loop that calls `onDisconnect` when a
|
|
16
|
+
* PowerLine becomes unreachable. Optionally calls `onHeartbeatComplete`
|
|
17
|
+
* after each tick (used for auto-reconnect of disconnected environments).
|
|
18
|
+
*/
|
|
19
|
+
export declare function startHeartbeat(onDisconnect: (environmentId: string) => void, onHeartbeatComplete?: () => Promise<void>): void;
|
|
16
20
|
/** Stop the periodic health-check loop. */
|
|
17
21
|
export declare function stopHeartbeat(): void;
|
|
18
22
|
//# sourceMappingURL=adapter-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter-manager.d.ts","sourceRoot":"","sources":["../src/adapter-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAUvF,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEjE;AAED,sDAAsD;AACtD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEvE;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAEpF;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAEpF;AAED,uDAAuD;AACvD,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAElE;AAED
|
|
1
|
+
{"version":3,"file":"adapter-manager.d.ts","sourceRoot":"","sources":["../src/adapter-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAUvF,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEjE;AAED,sDAAsD;AACtD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEvE;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAEpF;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAEpF;AAED,uDAAuD;AACvD,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAElE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,EAC7C,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACxC,IAAI,CAsCN;AAED,2CAA2C;AAC3C,wBAAgB,aAAa,IAAI,IAAI,CAKpC"}
|
package/dist/adapter-manager.js
CHANGED
|
@@ -28,8 +28,12 @@ export function removeConnection(environmentId) {
|
|
|
28
28
|
export function listConnections() {
|
|
29
29
|
return connections;
|
|
30
30
|
}
|
|
31
|
-
/**
|
|
32
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Start a periodic health-check loop that calls `onDisconnect` when a
|
|
33
|
+
* PowerLine becomes unreachable. Optionally calls `onHeartbeatComplete`
|
|
34
|
+
* after each tick (used for auto-reconnect of disconnected environments).
|
|
35
|
+
*/
|
|
36
|
+
export function startHeartbeat(onDisconnect, onHeartbeatComplete) {
|
|
33
37
|
if (heartbeatInterval !== undefined) {
|
|
34
38
|
return;
|
|
35
39
|
}
|
|
@@ -56,6 +60,15 @@ export function startHeartbeat(onDisconnect) {
|
|
|
56
60
|
onDisconnect(environmentId);
|
|
57
61
|
}
|
|
58
62
|
}
|
|
63
|
+
// After health checks, attempt reconnection of disconnected environments
|
|
64
|
+
if (onHeartbeatComplete) {
|
|
65
|
+
try {
|
|
66
|
+
await onHeartbeatComplete();
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
logger.error({ err }, "onHeartbeatComplete callback failed");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
59
72
|
}, HEARTBEAT_INTERVAL_MS);
|
|
60
73
|
}
|
|
61
74
|
/** Stop the periodic health-check loop. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter-manager.js","sourceRoot":"","sources":["../src/adapter-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,qBAAqB,GAAW,MAAM,CAAC;AAE7C,MAAM,QAAQ,GAAoC,IAAI,GAAG,EAA8B,CAAC;AACxF,MAAM,WAAW,GAAqC,IAAI,GAAG,EAA+B,CAAC;AAC7F,IAAI,iBAAiB,GAA+C,SAAS,CAAC;AAE9E,sEAAsE;AACtE,MAAM,UAAU,eAAe,CAAC,OAA2B;IACzD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,aAAa,CAAC,aAAqB,EAAE,IAAyB;IAC5E,WAAW,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,aAAqB;IACjD,OAAO,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AACxC,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,gBAAgB,CAAC,aAAqB;IACpD,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AACpC,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,eAAe;IAC7B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"adapter-manager.js","sourceRoot":"","sources":["../src/adapter-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scan for disconnected environments and attempt to reconnect eligible ones.
|
|
3
|
+
* Called after each heartbeat tick. Uses exponential backoff per environment
|
|
4
|
+
* and a concurrency lock to prevent overlapping attempts.
|
|
5
|
+
*
|
|
6
|
+
* Fire-and-forget for each environment — logs errors but does not throw.
|
|
7
|
+
*/
|
|
8
|
+
export declare function attemptReconnects(): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Clear reconnect state for an environment. Call when the environment is
|
|
11
|
+
* manually provisioned, removed, or otherwise taken out of the reconnect cycle.
|
|
12
|
+
*/
|
|
13
|
+
export declare function clearReconnectState(environmentId: string): void;
|
|
14
|
+
/** @internal Reset all reconnect state for testing. */
|
|
15
|
+
export declare function _resetForTesting(): void;
|
|
16
|
+
//# sourceMappingURL=auto-reconnect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-reconnect.d.ts","sourceRoot":"","sources":["../src/auto-reconnect.ts"],"names":[],"mappings":"AAwCA;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4CvD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAK/D;AAED,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { reconnectOrProvision } from "@grackle-ai/adapter-sdk";
|
|
2
|
+
import * as envRegistry from "./env-registry.js";
|
|
3
|
+
import * as adapterManager from "./adapter-manager.js";
|
|
4
|
+
import * as tokenBroker from "./token-broker.js";
|
|
5
|
+
import { recoverSuspendedSessions } from "./session-recovery.js";
|
|
6
|
+
import { emit } from "./event-bus.js";
|
|
7
|
+
import { logger } from "./logger.js";
|
|
8
|
+
// ─── Constants ──────────────────────────────────────────────
|
|
9
|
+
/** Initial delay before first reconnect attempt (milliseconds). */
|
|
10
|
+
const RECONNECT_INITIAL_DELAY_MS = 10_000;
|
|
11
|
+
/** Maximum number of reconnect attempts before giving up. */
|
|
12
|
+
const RECONNECT_MAX_RETRIES = 5;
|
|
13
|
+
/** Maximum delay between reconnect attempts (milliseconds). */
|
|
14
|
+
const RECONNECT_MAX_DELAY_MS = 120_000;
|
|
15
|
+
/** Multiplier for exponential backoff. */
|
|
16
|
+
const RECONNECT_BACKOFF_MULTIPLIER = 2;
|
|
17
|
+
/** Tracks reconnect backoff state per environment. */
|
|
18
|
+
const reconnectStates = new Map();
|
|
19
|
+
/** Prevents concurrent reconnect attempts for the same environment. */
|
|
20
|
+
const reconnecting = new Set();
|
|
21
|
+
// ─── Public API ─────────────────────────────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* Scan for disconnected environments and attempt to reconnect eligible ones.
|
|
24
|
+
* Called after each heartbeat tick. Uses exponential backoff per environment
|
|
25
|
+
* and a concurrency lock to prevent overlapping attempts.
|
|
26
|
+
*
|
|
27
|
+
* Fire-and-forget for each environment — logs errors but does not throw.
|
|
28
|
+
*/
|
|
29
|
+
export async function attemptReconnects() {
|
|
30
|
+
const environments = envRegistry.listEnvironments();
|
|
31
|
+
const disconnected = environments.filter((env) => env.status === "disconnected");
|
|
32
|
+
for (const env of disconnected) {
|
|
33
|
+
const state = reconnectStates.get(env.id);
|
|
34
|
+
// First time seeing this environment disconnected — initialize state with delay
|
|
35
|
+
if (!state) {
|
|
36
|
+
reconnectStates.set(env.id, {
|
|
37
|
+
attempts: 0,
|
|
38
|
+
nextRetryAt: Date.now() + RECONNECT_INITIAL_DELAY_MS,
|
|
39
|
+
});
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// Backoff not elapsed yet
|
|
43
|
+
if (Date.now() < state.nextRetryAt) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
// Max retries exhausted
|
|
47
|
+
if (state.attempts >= RECONNECT_MAX_RETRIES) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Already reconnecting
|
|
51
|
+
if (reconnecting.has(env.id)) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// Attempt reconnect (fire-and-forget)
|
|
55
|
+
tryReconnect(env.id).catch((err) => {
|
|
56
|
+
logger.error({ environmentId: env.id, err }, "Unhandled error during auto-reconnect");
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Clean up state for environments that are no longer disconnected
|
|
60
|
+
for (const [envId] of reconnectStates) {
|
|
61
|
+
const env = environments.find((e) => e.id === envId);
|
|
62
|
+
if (env?.status !== "disconnected") {
|
|
63
|
+
reconnectStates.delete(envId);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Clear reconnect state for an environment. Call when the environment is
|
|
69
|
+
* manually provisioned, removed, or otherwise taken out of the reconnect cycle.
|
|
70
|
+
*/
|
|
71
|
+
export function clearReconnectState(environmentId) {
|
|
72
|
+
reconnectStates.delete(environmentId);
|
|
73
|
+
// Note: does not cancel an in-flight tryReconnect — the lock will
|
|
74
|
+
// prevent a new attempt from starting, and the in-flight one will
|
|
75
|
+
// complete or fail on its own.
|
|
76
|
+
}
|
|
77
|
+
/** @internal Reset all reconnect state for testing. */
|
|
78
|
+
export function _resetForTesting() {
|
|
79
|
+
reconnectStates.clear();
|
|
80
|
+
reconnecting.clear();
|
|
81
|
+
}
|
|
82
|
+
// ─── Internal ───────────────────────────────────────────────
|
|
83
|
+
/**
|
|
84
|
+
* Attempt to reconnect a single disconnected environment.
|
|
85
|
+
* Uses the existing `reconnectOrProvision` flow from adapter-sdk.
|
|
86
|
+
*/
|
|
87
|
+
async function tryReconnect(environmentId) {
|
|
88
|
+
reconnecting.add(environmentId);
|
|
89
|
+
try {
|
|
90
|
+
// Re-fetch environment in case it was removed while waiting
|
|
91
|
+
const env = envRegistry.getEnvironment(environmentId);
|
|
92
|
+
if (!env) {
|
|
93
|
+
reconnectStates.delete(environmentId);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const adapter = adapterManager.getAdapter(env.adapterType);
|
|
97
|
+
if (!adapter) {
|
|
98
|
+
logger.warn({ environmentId, adapterType: env.adapterType }, "No adapter registered — skipping reconnect");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
logger.info({ environmentId, adapterType: env.adapterType }, "Attempting auto-reconnect");
|
|
102
|
+
envRegistry.updateEnvironmentStatus(environmentId, "connecting");
|
|
103
|
+
emit("environment.changed", {});
|
|
104
|
+
const config = JSON.parse(env.adapterConfig);
|
|
105
|
+
config.defaultRuntime = env.defaultRuntime;
|
|
106
|
+
const powerlineToken = env.powerlineToken;
|
|
107
|
+
// Run reconnectOrProvision — tries fast reconnect if supported, falls back to provision
|
|
108
|
+
for await (const event of reconnectOrProvision(environmentId, adapter, config, powerlineToken, !!env.bootstrapped)) {
|
|
109
|
+
logger.debug({ environmentId, stage: event.stage, message: event.message }, "Reconnect progress");
|
|
110
|
+
}
|
|
111
|
+
// Establish gRPC connection
|
|
112
|
+
const conn = await adapter.connect(environmentId, config, powerlineToken);
|
|
113
|
+
adapterManager.setConnection(environmentId, conn);
|
|
114
|
+
// Push tokens (local environments exclude file tokens)
|
|
115
|
+
if (env.adapterType === "local") {
|
|
116
|
+
await tokenBroker.pushToEnv(environmentId, { excludeFileTokens: true });
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
await tokenBroker.pushToEnv(environmentId);
|
|
120
|
+
}
|
|
121
|
+
envRegistry.updateEnvironmentStatus(environmentId, "connected");
|
|
122
|
+
envRegistry.markBootstrapped(environmentId);
|
|
123
|
+
emit("environment.changed", {});
|
|
124
|
+
// Auto-recover suspended sessions (fire-and-forget)
|
|
125
|
+
recoverSuspendedSessions(environmentId, conn).catch((err) => {
|
|
126
|
+
logger.error({ environmentId, err }, "Session recovery failed after auto-reconnect");
|
|
127
|
+
});
|
|
128
|
+
logger.info({ environmentId }, "Auto-reconnect successful");
|
|
129
|
+
reconnectStates.delete(environmentId);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
// Clean up any partially-established connection to avoid leaking state
|
|
133
|
+
adapterManager.removeConnection(environmentId);
|
|
134
|
+
const state = reconnectStates.get(environmentId) ?? { attempts: 0, nextRetryAt: 0 };
|
|
135
|
+
state.attempts++;
|
|
136
|
+
if (state.attempts >= RECONNECT_MAX_RETRIES) {
|
|
137
|
+
logger.error({ environmentId, attempts: state.attempts, err }, "Auto-reconnect exhausted all retries — giving up");
|
|
138
|
+
envRegistry.updateEnvironmentStatus(environmentId, "error");
|
|
139
|
+
emit("environment.changed", {});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const delay = Math.min(RECONNECT_INITIAL_DELAY_MS * Math.pow(RECONNECT_BACKOFF_MULTIPLIER, state.attempts), RECONNECT_MAX_DELAY_MS);
|
|
143
|
+
state.nextRetryAt = Date.now() + delay;
|
|
144
|
+
reconnectStates.set(environmentId, state);
|
|
145
|
+
logger.info({ environmentId, attempts: state.attempts, nextRetryInMs: delay, err }, "Auto-reconnect failed — will retry");
|
|
146
|
+
envRegistry.updateEnvironmentStatus(environmentId, "disconnected");
|
|
147
|
+
emit("environment.changed", {});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
reconnecting.delete(environmentId);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=auto-reconnect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-reconnect.js","sourceRoot":"","sources":["../src/auto-reconnect.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grpc-service.d.ts","sourceRoot":"","sources":["../src/grpc-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA+
|
|
1
|
+
{"version":3,"file":"grpc-service.d.ts","sourceRoot":"","sources":["../src/grpc-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA+F7E;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYvD;AAqLD,gFAAgF;AAChF,wBAAgB,mBAAmB,CACjC,UAAU,EAAE;IACV,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,EAAE,GACF,MAAM,CAUR;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAczE;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAghDjE"}
|
package/dist/grpc-service.js
CHANGED
|
@@ -16,6 +16,7 @@ import { emit } from "./event-bus.js";
|
|
|
16
16
|
import { processEventStream } from "./event-processor.js";
|
|
17
17
|
import * as processorRegistry from "./processor-registry.js";
|
|
18
18
|
import { recoverSuspendedSessions } from "./session-recovery.js";
|
|
19
|
+
import { clearReconnectState } from "./auto-reconnect.js";
|
|
19
20
|
import { join } from "node:path";
|
|
20
21
|
import { LOGS_DIR, DEFAULT_WEB_PORT, DEFAULT_MCP_PORT, MAX_TASK_DEPTH, SESSION_STATUS, TERMINAL_SESSION_STATUSES, TASK_STATUS, ROOT_TASK_ID, taskStatusToEnum, taskStatusToString, workspaceStatusToEnum, claudeProviderModeToEnum, providerToggleToEnum, } from "@grackle-ai/common";
|
|
21
22
|
import { resolvePersona } from "./resolve-persona.js";
|
|
@@ -29,6 +30,8 @@ import { computeTaskStatus } from "./compute-task-status.js";
|
|
|
29
30
|
import { loadOrCreateApiKey } from "./api-key.js";
|
|
30
31
|
import { logger } from "./logger.js";
|
|
31
32
|
import { reanimateAgent } from "./reanimate-agent.js";
|
|
33
|
+
import { getKnowledgeEmbedder, isKnowledgeEnabled } from "./knowledge-init.js";
|
|
34
|
+
import { knowledgeSearch, getNode as getKnowledgeNodeById, expandNode, createNativeNode, ingest, createPassThroughChunker, listRecentNodes, } from "@grackle-ai/knowledge";
|
|
32
35
|
import { slugify } from "./utils/slugify.js";
|
|
33
36
|
import { SystemPromptBuilder, buildTaskPrompt } from "./system-prompt-builder.js";
|
|
34
37
|
import { importGitHubIssues as executeGitHubImport } from "./github-import.js";
|
|
@@ -269,6 +272,8 @@ export function registerGrackleRoutes(router) {
|
|
|
269
272
|
if (wsCount > 0) {
|
|
270
273
|
throw new ConnectError(`Cannot remove environment: ${wsCount} active workspace(s) still reference it. Archive or reparent them first.`, Code.FailedPrecondition);
|
|
271
274
|
}
|
|
275
|
+
// Stop auto-reconnect attempts for this environment
|
|
276
|
+
clearReconnectState(req.id);
|
|
272
277
|
// Disconnect the adapter if currently connected
|
|
273
278
|
const env = envRegistry.getEnvironment(req.id);
|
|
274
279
|
if (env) {
|
|
@@ -291,6 +296,8 @@ export function registerGrackleRoutes(router) {
|
|
|
291
296
|
return create(grackle.EmptySchema, {});
|
|
292
297
|
},
|
|
293
298
|
async *provisionEnvironment(req) {
|
|
299
|
+
// Manual provision overrides auto-reconnect
|
|
300
|
+
clearReconnectState(req.id);
|
|
294
301
|
const env = envRegistry.getEnvironment(req.id);
|
|
295
302
|
if (!env) {
|
|
296
303
|
yield create(grackle.ProvisionEventSchema, {
|
|
@@ -1360,6 +1367,110 @@ export function registerGrackleRoutes(router) {
|
|
|
1360
1367
|
const url = `http://${pairingHost}:${webPort}/pair?code=${code}`;
|
|
1361
1368
|
return create(grackle.PairingCodeResponseSchema, { code, url });
|
|
1362
1369
|
},
|
|
1370
|
+
// ── Knowledge Graph ────────────────────────────────────────
|
|
1371
|
+
async searchKnowledge(req) {
|
|
1372
|
+
const embedder = getKnowledgeEmbedder();
|
|
1373
|
+
if (!embedder) {
|
|
1374
|
+
throw new ConnectError("Knowledge graph not available", Code.Unavailable);
|
|
1375
|
+
}
|
|
1376
|
+
const results = await knowledgeSearch(req.query, embedder, {
|
|
1377
|
+
limit: req.limit || 10,
|
|
1378
|
+
workspaceId: req.workspaceId || undefined,
|
|
1379
|
+
});
|
|
1380
|
+
return create(grackle.SearchKnowledgeResponseSchema, {
|
|
1381
|
+
results: results.map((r) => create(grackle.SearchKnowledgeResultSchema, {
|
|
1382
|
+
score: r.score,
|
|
1383
|
+
node: knowledgeNodeToProto(r.node),
|
|
1384
|
+
edges: r.edges.map(knowledgeEdgeToProto),
|
|
1385
|
+
})),
|
|
1386
|
+
});
|
|
1387
|
+
},
|
|
1388
|
+
async getKnowledgeNode(req) {
|
|
1389
|
+
if (!isKnowledgeEnabled()) {
|
|
1390
|
+
throw new ConnectError("Knowledge graph not available", Code.Unavailable);
|
|
1391
|
+
}
|
|
1392
|
+
const result = await getKnowledgeNodeById(req.id);
|
|
1393
|
+
if (!result) {
|
|
1394
|
+
throw new ConnectError(`Knowledge node not found: ${req.id}`, Code.NotFound);
|
|
1395
|
+
}
|
|
1396
|
+
return create(grackle.GetKnowledgeNodeResponseSchema, {
|
|
1397
|
+
node: knowledgeNodeToProto(result.node),
|
|
1398
|
+
edges: result.edges.map(knowledgeEdgeToProto),
|
|
1399
|
+
});
|
|
1400
|
+
},
|
|
1401
|
+
async expandKnowledgeNode(req) {
|
|
1402
|
+
if (!isKnowledgeEnabled()) {
|
|
1403
|
+
throw new ConnectError("Knowledge graph not available", Code.Unavailable);
|
|
1404
|
+
}
|
|
1405
|
+
const result = await expandNode(req.id, {
|
|
1406
|
+
depth: req.depth || 1,
|
|
1407
|
+
edgeTypes: req.edgeTypes.length > 0 ? req.edgeTypes : undefined,
|
|
1408
|
+
});
|
|
1409
|
+
return create(grackle.ExpandKnowledgeNodeResponseSchema, {
|
|
1410
|
+
nodes: result.nodes.map(knowledgeNodeToProto),
|
|
1411
|
+
edges: result.edges.map(knowledgeEdgeToProto),
|
|
1412
|
+
});
|
|
1413
|
+
},
|
|
1414
|
+
async listRecentKnowledgeNodes(req) {
|
|
1415
|
+
if (!isKnowledgeEnabled()) {
|
|
1416
|
+
throw new ConnectError("Knowledge graph not available", Code.Unavailable);
|
|
1417
|
+
}
|
|
1418
|
+
const result = await listRecentNodes(req.limit || 20, req.workspaceId || undefined);
|
|
1419
|
+
return create(grackle.ListRecentKnowledgeNodesResponseSchema, {
|
|
1420
|
+
nodes: result.nodes.map(knowledgeNodeToProto),
|
|
1421
|
+
edges: result.edges.map(knowledgeEdgeToProto),
|
|
1422
|
+
});
|
|
1423
|
+
},
|
|
1424
|
+
async createKnowledgeNode(req) {
|
|
1425
|
+
const embedder = getKnowledgeEmbedder();
|
|
1426
|
+
if (!embedder) {
|
|
1427
|
+
throw new ConnectError("Knowledge graph not available", Code.Unavailable);
|
|
1428
|
+
}
|
|
1429
|
+
const chunker = createPassThroughChunker();
|
|
1430
|
+
const embedded = await ingest(req.content, chunker, embedder);
|
|
1431
|
+
if (embedded.length === 0) {
|
|
1432
|
+
throw new ConnectError("Content produced no embeddings", Code.InvalidArgument);
|
|
1433
|
+
}
|
|
1434
|
+
const id = await createNativeNode({
|
|
1435
|
+
category: (req.category || "insight"),
|
|
1436
|
+
title: req.title,
|
|
1437
|
+
content: req.content,
|
|
1438
|
+
tags: [...req.tags],
|
|
1439
|
+
embedding: embedded[0].vector,
|
|
1440
|
+
workspaceId: req.workspaceId || "",
|
|
1441
|
+
});
|
|
1442
|
+
return create(grackle.CreateKnowledgeNodeResponseSchema, { id });
|
|
1443
|
+
},
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
// ---------------------------------------------------------------------------
|
|
1447
|
+
// Knowledge graph proto converters
|
|
1448
|
+
// ---------------------------------------------------------------------------
|
|
1449
|
+
/** Convert a KnowledgeNode to its proto representation. */
|
|
1450
|
+
function knowledgeNodeToProto(node) {
|
|
1451
|
+
return create(grackle.KnowledgeNodeProtoSchema, {
|
|
1452
|
+
id: node.id,
|
|
1453
|
+
kind: node.kind,
|
|
1454
|
+
workspaceId: node.workspaceId,
|
|
1455
|
+
createdAt: node.createdAt,
|
|
1456
|
+
updatedAt: node.updatedAt,
|
|
1457
|
+
sourceType: node.kind === "reference" ? node.sourceType : "",
|
|
1458
|
+
sourceId: node.kind === "reference" ? node.sourceId : "",
|
|
1459
|
+
label: node.kind === "reference" ? node.label : "",
|
|
1460
|
+
category: node.kind === "native" ? node.category : "",
|
|
1461
|
+
title: node.kind === "native" ? node.title : "",
|
|
1462
|
+
content: node.kind === "native" ? node.content : "",
|
|
1463
|
+
tags: node.kind === "native" ? node.tags : [],
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
/** Convert a KnowledgeEdge to its proto representation. */
|
|
1467
|
+
function knowledgeEdgeToProto(edge) {
|
|
1468
|
+
return create(grackle.KnowledgeEdgeProtoSchema, {
|
|
1469
|
+
fromId: edge.fromId,
|
|
1470
|
+
toId: edge.toId,
|
|
1471
|
+
type: edge.type,
|
|
1472
|
+
metadataJson: edge.metadata ? JSON.stringify(edge.metadata) : "",
|
|
1473
|
+
createdAt: edge.createdAt,
|
|
1363
1474
|
});
|
|
1364
1475
|
}
|
|
1365
1476
|
//# sourceMappingURL=grpc-service.js.map
|