Compare commits

...

3 Commits

Author SHA1 Message Date
Rob Colbert
2a2bbcd075 subprocess maintenance 2026-05-26 16:53:01 -04:00
Rob Colbert
3be6ebbffa Docker Compose YAML that specifies Qdrant config 2026-05-19 17:22:52 -04:00
Rob Colbert
1e5082c820 switch to UUID for point IDs 2026-05-19 17:10:08 -04:00
5 changed files with 47 additions and 13 deletions

22
compose.yaml Normal file
View File

@ -0,0 +1,22 @@
services:
qdrant:
image: qdrant/qdrant:latest
restart: always
container_name: qdrant
ports:
- 6333:6333
- 6334:6334
expose:
- 6333
- 6334
- 6335
configs:
- source: qdrant_config
target: /qdrant/config/production.yaml
volumes:
- ./qdrant_data:/qdrant/storage
configs:
qdrant_config:
content: |
log_level: INFO

View File

@ -2,6 +2,8 @@
// Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us> // Copyright (C) 2026 Robert Colbert <rob.colbert@openplatform.us>
// All Rights Reserved // All Rights Reserved
import crypto from "node:crypto";
import { QdrantClient } from "@qdrant/js-client-rest"; import { QdrantClient } from "@qdrant/js-client-rest";
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters"; import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
@ -360,7 +362,7 @@ class VectorStoreService extends DtpService {
} }
points.push({ points.push({
id: `${turnId}:${i}`, id: crypto.randomUUID(),
vector: embedding, vector: embedding,
payload: { payload: {
content: chunk, content: chunk,

View File

@ -696,6 +696,11 @@ class GadgetDrone extends GadgetProcess {
process.exit(exitCode); process.exit(exitCode);
}); });
process.on("uncaughtException", (error) => {
this.log.fatal("uncaught exception", { err: error });
process.exit(1);
});
process.on("warning", (error) => { process.on("warning", (error) => {
if (error.name === "DeprecationWarning") return; if (error.name === "DeprecationWarning") return;
this.log.alert("warning", { error }); this.log.alert("warning", { error });

View File

@ -2,8 +2,6 @@
// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us> // Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
// Licensed under the Apache License, Version 2.0 // Licensed under the Apache License, Version 2.0
import assert from "node:assert";
import path from "node:path"; import path from "node:path";
import fs from "node:fs"; import fs from "node:fs";
@ -63,17 +61,24 @@ class SubProcessService extends GadgetService {
args?: string[], args?: string[],
): Promise<SubProcess> { ): Promise<SubProcess> {
const NOW = new Date(); const NOW = new Date();
assert( const gadgetDir = WorkspaceService.gadgetDir;
WorkspaceService.gadgetDir, if (!gadgetDir) {
"Gadget workspace directory not initialized", throw new Error("Gadget workspace directory not initialized");
); }
const logDir = path.join(WorkspaceService.gadgetDir, "subprocess-logs"); const logDir = path.join(gadgetDir, "subprocess-logs");
await fs.promises.mkdir(logDir, { recursive: true }); await fs.promises.mkdir(logDir, { recursive: true });
const projectDir = WorkspaceService.getProjectDirectory(project.slug); const projectDir = WorkspaceService.getProjectDirectory(project.slug);
const child = spawn(cmd, args, { cwd: projectDir }); const spawnArgs = args ?? [];
assert(child.pid, "subprocess did not define a process id"); const useShell = spawnArgs.length === 0;
const child = spawn(cmd, spawnArgs, { cwd: projectDir, shell: useShell });
child.on("error", (err) => {
this.log.error("subprocess spawn failed", { cmd, args, error: err.message });
});
if (!child.pid) {
throw new Error("Failed to spawn subprocess: child process has no pid");
}
const pid = child.pid; const pid = child.pid;
const stdoutFileName = path.join(logDir, `subproc-${pid}.stdout.log`); const stdoutFileName = path.join(logDir, `subproc-${pid}.stdout.log`);

View File

@ -45,7 +45,7 @@ export class SubprocessTool extends GadgetTool {
command: { command: {
type: "string", type: "string",
description: description:
"The shell command to execute (required for cmd=create). Example: 'node', 'npm', 'python', './my-server'.", "The full shell command to execute (required for cmd=create). Examples: 'npm run dev', 'pnpm dev:frontend', 'node server.js'. The command is executed via /bin/sh.",
}, },
args: { args: {
type: "array", type: "array",
@ -128,7 +128,7 @@ export class SubprocessTool extends GadgetTool {
message: "The 'command' parameter is required for cmd=create.", message: "The 'command' parameter is required for cmd=create.",
parameter: "command", parameter: "command",
recoveryHint: recoveryHint:
"Provide the command to execute, e.g. 'node', 'npm', 'python'.", "Provide the full command string to execute, e.g. 'npm run dev', 'pnpm dev:frontend'. The command is executed via /bin/sh.",
}); });
} }
@ -168,7 +168,7 @@ export class SubprocessTool extends GadgetTool {
}); });
return formatError({ return formatError({
code: "OPERATION_FAILED", code: "OPERATION_FAILED",
message: `Failed to spawn subprocess: ${message}`, message: `Failed to spawn subprocess: ${message}. Make sure the command is installed and available in PATH, or use the full path to the executable.`,
}); });
} }
} }