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>
// All Rights Reserved
import crypto from "node:crypto";
import { QdrantClient } from "@qdrant/js-client-rest";
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
@ -360,7 +362,7 @@ class VectorStoreService extends DtpService {
}
points.push({
id: `${turnId}:${i}`,
id: crypto.randomUUID(),
vector: embedding,
payload: {
content: chunk,

View File

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

View File

@ -2,8 +2,6 @@
// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
// Licensed under the Apache License, Version 2.0
import assert from "node:assert";
import path from "node:path";
import fs from "node:fs";
@ -63,17 +61,24 @@ class SubProcessService extends GadgetService {
args?: string[],
): Promise<SubProcess> {
const NOW = new Date();
assert(
WorkspaceService.gadgetDir,
"Gadget workspace directory not initialized",
);
const gadgetDir = WorkspaceService.gadgetDir;
if (!gadgetDir) {
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 });
const projectDir = WorkspaceService.getProjectDirectory(project.slug);
const child = spawn(cmd, args, { cwd: projectDir });
assert(child.pid, "subprocess did not define a process id");
const spawnArgs = args ?? [];
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 stdoutFileName = path.join(logDir, `subproc-${pid}.stdout.log`);

View File

@ -45,7 +45,7 @@ export class SubprocessTool extends GadgetTool {
command: {
type: "string",
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: {
type: "array",
@ -128,7 +128,7 @@ export class SubprocessTool extends GadgetTool {
message: "The 'command' parameter is required for cmd=create.",
parameter: "command",
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({
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.`,
});
}
}