Compare commits

..

1 Commits

Author SHA1 Message Date
xiaoju 1b8f327259 docs: upgrade debate example — 3 roles, oneOf routing, bounded termination
Based on xiaonuo's battle-tested debate workflow. Changes:
- 3 roles (proponent/opponent/host) instead of 2
- oneOf + const schema (speak/conceded/final) instead of enum
- Bounded: 3rd speech forces final statement
- Host role delivers summary/highlights/verdict
- Critical thinking framework in procedure
- Edge prompts pass structured data via {{{argument}}}/{{{closing}}}
2026-06-06 03:01:37 +00:00
11 changed files with 57 additions and 80 deletions
+12
View File
@@ -0,0 +1,12 @@
---
"@united-workforce/agent-hermes": patch
"@united-workforce/agent-claude-code": patch
"@united-workforce/util-agent": patch
---
feat: inject thread progress into agent prompt (#127)
Agents now receive a "Thread Progress" section in their prompt showing the
current step number and how many times the current role has spoken before.
This eliminates the need for agents to make tool calls (terminal, delegate_task)
just to count their own turn history.
+37 -28
View File
@@ -1,22 +1,5 @@
name: debate
description: "Multi-role structured debate with critical thinking framework and host summary."
# Shared frontmatter schema for debater roles (YAML anchor)
x-debater-frontmatter: &debater-frontmatter
type: object
oneOf:
- properties:
$status: { const: speak }
argument: { type: string }
required: [$status, argument]
- properties:
$status: { const: conceded }
reason: { type: string }
required: [$status, reason]
- properties:
$status: { const: final }
closing: { type: string }
required: [$status, closing]
description: "Structured two-side debate with host summary. Demonstrates multi-role coordination, oneOf output routing, and bounded termination."
roles:
proponent:
@@ -26,13 +9,12 @@ roles:
procedure: |
You are an experienced scholar arguing FOR the proposition.
## Critical Thinking Framework (execute before every speech)
## Critical Thinking Framework (apply before every response)
### A. Pre-speech reflection (internal, do not output)
- Does every step in my argument chain hold? Any hidden assumptions or logical gaps?
### A. Pre-response reflection (internal, do not output)
- Does every step in my argument chain hold? Any hidden assumptions?
- If I were my opponent, how would I attack this? Where am I weakest?
- Does my evidence actually support my claim, or could it backfire?
- Should I go on offense or defense this round?
### B. Evidence discipline
- Verify key numbers — watch for order-of-magnitude errors
@@ -50,7 +32,21 @@ roles:
4. Otherwise output $status: speak and counter the opponent's points.
5. Be rigorous, cite evidence, stay concise.
output: "Debate argument"
frontmatter: *debater-frontmatter
frontmatter:
type: object
oneOf:
- properties:
$status: { const: speak }
argument: { type: string }
required: [$status, argument]
- properties:
$status: { const: conceded }
reason: { type: string }
required: [$status, reason]
- properties:
$status: { const: final }
closing: { type: string }
required: [$status, closing]
opponent:
description: "Argues AGAINST the proposition"
@@ -59,13 +55,12 @@ roles:
procedure: |
You are an experienced scholar arguing AGAINST the proposition.
## Critical Thinking Framework (execute before every speech)
## Critical Thinking Framework (apply before every response)
### A. Pre-speech reflection (internal, do not output)
- Does every step in my argument chain hold? Any hidden assumptions or logical gaps?
### A. Pre-response reflection (internal, do not output)
- Does every step in my argument chain hold? Any hidden assumptions?
- If I were my opponent, how would I attack this? Where am I weakest?
- Does my evidence actually support my claim, or could it backfire?
- Should I go on offense or defense this round?
### B. Evidence discipline
- Verify key numbers — watch for order-of-magnitude errors
@@ -83,7 +78,21 @@ roles:
4. Otherwise output $status: speak and counter the proponent's points.
5. Be rigorous, cite evidence, stay concise.
output: "Debate argument"
frontmatter: *debater-frontmatter
frontmatter:
type: object
oneOf:
- properties:
$status: { const: speak }
argument: { type: string }
required: [$status, argument]
- properties:
$status: { const: conceded }
reason: { type: string }
required: [$status, reason]
- properties:
$status: { const: final }
closing: { type: string }
required: [$status, closing]
host:
description: "Debate moderator — delivers impartial summary and verdict"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@united-workforce/agent-claude-code",
"version": "0.1.3",
"version": "0.1.2",
"files": [
"src",
"dist",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@united-workforce/agent-hermes",
"version": "0.1.4",
"version": "0.1.3",
"files": [
"src",
"dist",
+2 -7
View File
@@ -12,11 +12,7 @@ const OWN_VERSION = (
}
).version;
/** Resolve hermes binary: `UWF_HERMES_BIN` override → default `"hermes"` via PATH. */
function resolveHermesCommand(): string {
const override = process.env.UWF_HERMES_BIN;
return override !== undefined && override !== "" ? override : "hermes";
}
const HERMES_COMMAND = "hermes";
const PROTOCOL_VERSION = 1;
type JsonRpcResponse = {
@@ -275,8 +271,7 @@ export class HermesAcpClient {
return;
}
const hermesCommand = resolveHermesCommand();
const child = spawn(hermesCommand, ["acp"], {
const child = spawn(HERMES_COMMAND, ["acp"], {
env: process.env,
shell: false,
stdio: ["pipe", "pipe", "pipe"],
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@united-workforce/eval",
"version": "0.1.4",
"version": "0.1.3",
"private": false,
"files": [
"src",
+1 -1
View File
@@ -6,7 +6,7 @@ import { formatList, selectEntries } from "./format.js";
import { readEvalEntries } from "./read.js";
const log = createLogger({ sink: { kind: "stderr" } });
const LOG_LIST = "H5KX9R2B";
const LOG_LIST = "L5KX9R2B";
type ListCliOptions = {
task: string | undefined;
@@ -225,34 +225,4 @@ describe("buildOutputFormatInstruction", () => {
const result = buildOutputFormatInstruction({});
expect(result).toContain("Focus exclusively on YOUR role");
});
test("renders const value as literal in flat schema example", () => {
const schema = {
type: "object",
properties: {
$status: { type: "string", const: "greeted" },
message: { type: "string" },
},
required: ["$status", "message"],
};
const result = buildOutputFormatInstruction(schema);
expect(result).toContain("$status: greeted");
expect(result).toContain("fixed value");
expect(result).not.toContain("$status: <string>");
});
test("renders const value for non-string types", () => {
const schema = {
type: "object",
properties: {
count: { type: "number", const: 42 },
done: { type: "boolean", const: true },
},
required: ["count", "done"],
};
const result = buildOutputFormatInstruction(schema);
expect(result).toContain("count: 42");
expect(result).toContain("done: true");
expect(result).toContain("fixed value");
});
});
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@united-workforce/util-agent",
"version": "0.1.1",
"version": "0.1.0",
"files": [
"src",
"dist",
@@ -74,10 +74,6 @@ function collectObjectSchemas(schema: JSONSchema): JSONSchema[] {
}
function resolvePropertySchema(prop: JSONSchema): JSONSchema {
if (prop.const !== undefined) {
return prop;
}
if (Array.isArray(prop.enum) && prop.enum.length > 0) {
return prop;
}
@@ -117,11 +113,6 @@ function buildPropertyExampleLine(prop: SchemaProperty): string {
commentParts.push("required");
}
if (resolved.const !== undefined) {
commentParts.push("fixed value");
return `${prop.name}: ${formatYamlScalar(resolved.const)}${buildPropertyComment(commentParts)}`;
}
if (Array.isArray(resolved.enum) && resolved.enum.length > 0) {
const enumValues = resolved.enum.map((v) => String(v));
commentParts.push(...enumValues);
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@united-workforce/util",
"version": "0.1.4",
"version": "0.1.3",
"files": [
"src",
"dist",