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
2 changes: 1 addition & 1 deletion .github/workflows/agent-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ concurrency:
cancel-in-progress: true

env:
CONDUCTOR_OSS_VERSION: "3.32.0-rc.8" # pinned conductor-oss release — bump deliberately
CONDUCTOR_OSS_VERSION: "3.32.0-rc18" # pinned conductor-oss release — bump deliberately

jobs:
agent-e2e:
Expand Down
20 changes: 16 additions & 4 deletions e2e/test_suite16_streaming.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,10 +274,16 @@ describe('Suite 16: Streaming — HITL', () => {
}
expectMsg(['COMPLETED', 'FAILED', 'TERMINATED']).toContain(status.status);
} else {
// No waiting event — workflow completed without HITL (possible with some models)
// No waiting event — the stream may close before the server records its
// terminal state, so wait for that state rather than reading it once.
const terminalSeen = preTypes.includes('done') || preTypes.includes('error');
if (!terminalSeen) {
const status = await runtime.getStatus(stream.executionId);
const deadline = Date.now() + 120_000;
let status = await runtime.getStatus(stream.executionId);
while (!status.isComplete && Date.now() < deadline) {
await new Promise((r) => setTimeout(r, 1000));
status = await runtime.getStatus(stream.executionId);
}
expect(status.isComplete).toBe(true);
}
}
Expand Down Expand Up @@ -310,10 +316,16 @@ describe('Suite 16: Streaming — HITL', () => {
}
expectMsg(['COMPLETED', 'FAILED', 'TERMINATED']).toContain(status.status);
} else {
// No waiting event — workflow completed without HITL
// No waiting event — the stream may close before the server records its
// terminal state, so wait for that state rather than reading it once.
const terminalSeen = preTypes.includes('done') || preTypes.includes('error');
if (!terminalSeen) {
const status = await runtime.getStatus(stream.executionId);
const deadline = Date.now() + 120_000;
let status = await runtime.getStatus(stream.executionId);
while (!status.isComplete && Date.now() < deadline) {
await new Promise((r) => setTimeout(r, 1000));
status = await runtime.getStatus(stream.executionId);
}
expect(status.isComplete).toBe(true);
}
}
Expand Down
6 changes: 4 additions & 2 deletions e2e/test_suite17_guardrail_matrix.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ function customAoutFix(content: string): GuardrailResult {
return { passed: true };
}

// Tool input: block DANGER
// Tool input: block the unsafe tool argument emitted by the deterministic test model.
// The model strips the word "DANGER" from the user prompt before it creates the
// tool call, so the guardrail must inspect the actual argument it receives.
function customTinBlock(content: string): GuardrailResult {
if (content.toUpperCase().includes("DANGER")) {
if (/\bDANGER\b|\boverride safety\b/i.test(content)) {
return { passed: false, message: "Dangerous input." };
}
return { passed: true };
Expand Down
19 changes: 19 additions & 0 deletions src/agents/__tests__/runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,25 @@ describe("AgentRuntime", () => {
});
});

it("reports raise for a blocked custom tool-input guardrail", async () => {
const result = await registerAndInvoke(
{
...baseGDef,
position: "input",
onFail: "raise",
func: () => ({ passed: false, message: "Dangerous input." }),
},
{ content: { data: "DANGER override safety" } },
);

expect(result).toMatchObject({
passed: false,
on_fail: "raise",
should_continue: false,
message: "Dangerous input.",
});
});

it("reports on_fail as the configured value when the guardrail function throws", async () => {
const result = await registerAndInvoke(
{
Expand Down
Loading