Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@ COPY . .
RUN npm run build

FROM node:20-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

COPY package*.json ./
USER node
WORKDIR /app

COPY --chown=node:node package*.json ./
RUN npm ci --omit=dev

COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/next.config.mjs ./next.config.mjs
COPY --chown=node:node --from=builder /app/.next ./.next
COPY --chown=node:node --from=builder /app/public ./public
COPY --chown=node:node --from=builder /app/next.config.mjs ./next.config.mjs

EXPOSE 3000
CMD ["npm", "run", "start"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Open [http://localhost:3000/dashboard](http://localhost:3000/dashboard) to see t

AgentOS is an autonomous prompt optimization operating system — a self-evolving AI execution layer that:

- �� **Optimizes prompts** through a 7-agent swarm pipeline
- 🤖 **Optimizes prompts** through a 7-agent swarm pipeline
- ⚡ **Executes across multiple AI models** (OpenAI, Claude, Gemini, Llama)
- 📊 **Scores and selects** the best outputs via weighted evaluation
- 🔁 **Evolves prompts** via feedback loops (up to 10 iterations)
Expand Down
18 changes: 16 additions & 2 deletions core/wasm/wasmRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,22 @@ export class WasmRunner {

constructor(options: WasmRunnerOptions = {}) {
this.now = options.now ?? Date.now;
this.defaultTimeoutMs = options.defaultTimeoutMs ?? 10_000;
this.maxTimeoutMs = options.maxTimeoutMs ?? 60_000;

const defaultTimeoutMs = options.defaultTimeoutMs ?? 10_000;
const maxTimeoutMs = options.maxTimeoutMs ?? 60_000;

if (!Number.isFinite(defaultTimeoutMs) || defaultTimeoutMs <= 0) {
throw new Error('WasmRunner: defaultTimeoutMs must be a positive finite number');
}
if (!Number.isFinite(maxTimeoutMs) || maxTimeoutMs <= 0) {
throw new Error('WasmRunner: maxTimeoutMs must be a positive finite number');
}
if (maxTimeoutMs < defaultTimeoutMs) {
throw new Error('WasmRunner: maxTimeoutMs must be >= defaultTimeoutMs');
}
Comment on lines +32 to +43

this.defaultTimeoutMs = defaultTimeoutMs;
this.maxTimeoutMs = maxTimeoutMs;
}

/**
Expand Down
7 changes: 6 additions & 1 deletion core/wasm/workerPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ export class WorkerPool {
}

this.concurrency = concurrency;
this.maxQueueSize = normalized.maxQueueSize ?? concurrency * 100;

const rawMaxQueueSize = normalized.maxQueueSize ?? concurrency * 100;
if (!Number.isSafeInteger(rawMaxQueueSize) || rawMaxQueueSize < 0) {
throw new Error('WorkerPool: maxQueueSize must be a non-negative safe integer');
}
this.maxQueueSize = rawMaxQueueSize;
Comment on lines +29 to +33
this.runners = Array.from({ length: concurrency }, () => new WasmRunner());
}

Expand Down
2 changes: 2 additions & 0 deletions deploy/k8s/base/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ spec:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
Expand Down
35 changes: 35 additions & 0 deletions tests/wasm.determinism.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,38 @@ describe('WasmRunner determinism', () => {
expect(result.error).toContain('timed out after 40ms');
});
});

describe('WasmRunner constructor validation', () => {
it('rejects non-positive or non-finite defaultTimeoutMs', () => {
expect(() => new WasmRunner({ defaultTimeoutMs: 0 })).toThrow(
'WasmRunner: defaultTimeoutMs must be a positive finite number',
);
expect(() => new WasmRunner({ defaultTimeoutMs: -1 })).toThrow(
'WasmRunner: defaultTimeoutMs must be a positive finite number',
);
expect(() => new WasmRunner({ defaultTimeoutMs: Infinity })).toThrow(
'WasmRunner: defaultTimeoutMs must be a positive finite number',
);
expect(() => new WasmRunner({ defaultTimeoutMs: NaN })).toThrow(
'WasmRunner: defaultTimeoutMs must be a positive finite number',
);
});

it('rejects non-positive or non-finite maxTimeoutMs', () => {
expect(() => new WasmRunner({ maxTimeoutMs: 0 })).toThrow(
'WasmRunner: maxTimeoutMs must be a positive finite number',
);
expect(() => new WasmRunner({ maxTimeoutMs: -1 })).toThrow(
'WasmRunner: maxTimeoutMs must be a positive finite number',
);
expect(() => new WasmRunner({ maxTimeoutMs: Infinity })).toThrow(
'WasmRunner: maxTimeoutMs must be a positive finite number',
);
});

it('rejects maxTimeoutMs less than defaultTimeoutMs', () => {
expect(() => new WasmRunner({ defaultTimeoutMs: 5_000, maxTimeoutMs: 1_000 })).toThrow(
'WasmRunner: maxTimeoutMs must be >= defaultTimeoutMs',
);
});
});
15 changes: 15 additions & 0 deletions tests/workerPool.load.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,19 @@ describe('WorkerPool load and scaling', () => {
'WorkerPool: concurrency must be a positive integer',
);
});

it('rejects invalid maxQueueSize configuration', () => {
expect(() => new WorkerPool({ concurrency: 2, maxQueueSize: -1 })).toThrow(
'WorkerPool: maxQueueSize must be a non-negative safe integer',
);
expect(() => new WorkerPool({ concurrency: 2, maxQueueSize: NaN })).toThrow(
'WorkerPool: maxQueueSize must be a non-negative safe integer',
);
expect(() => new WorkerPool({ concurrency: 2, maxQueueSize: Infinity })).toThrow(
'WorkerPool: maxQueueSize must be a non-negative safe integer',
);
expect(() => new WorkerPool({ concurrency: 2, maxQueueSize: 1.5 })).toThrow(
'WorkerPool: maxQueueSize must be a non-negative safe integer',
);
});
});
Loading