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
9 changed files with 55 additions and 78 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 name: debate
description: "Multi-role structured debate with critical thinking framework and host summary." description: "Structured two-side debate with host summary. Demonstrates multi-role coordination, oneOf output routing, and bounded termination."
# 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]
roles: roles:
proponent: proponent:
@@ -26,13 +9,12 @@ roles:
procedure: | procedure: |
You are an experienced scholar arguing FOR the proposition. 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) ### A. Pre-response reflection (internal, do not output)
- Does every step in my argument chain hold? Any hidden assumptions or logical gaps? - 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? - 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? - Does my evidence actually support my claim, or could it backfire?
- Should I go on offense or defense this round?
### B. Evidence discipline ### B. Evidence discipline
- Verify key numbers — watch for order-of-magnitude errors - 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. 4. Otherwise output $status: speak and counter the opponent's points.
5. Be rigorous, cite evidence, stay concise. 5. Be rigorous, cite evidence, stay concise.
output: "Debate argument" 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: opponent:
description: "Argues AGAINST the proposition" description: "Argues AGAINST the proposition"
@@ -59,13 +55,12 @@ roles:
procedure: | procedure: |
You are an experienced scholar arguing AGAINST the proposition. 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) ### A. Pre-response reflection (internal, do not output)
- Does every step in my argument chain hold? Any hidden assumptions or logical gaps? - 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? - 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? - Does my evidence actually support my claim, or could it backfire?
- Should I go on offense or defense this round?
### B. Evidence discipline ### B. Evidence discipline
- Verify key numbers — watch for order-of-magnitude errors - 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. 4. Otherwise output $status: speak and counter the proponent's points.
5. Be rigorous, cite evidence, stay concise. 5. Be rigorous, cite evidence, stay concise.
output: "Debate argument" 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: host:
description: "Debate moderator — delivers impartial summary and verdict" description: "Debate moderator — delivers impartial summary and verdict"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@united-workforce/agent-claude-code", "name": "@united-workforce/agent-claude-code",
"version": "0.1.3", "version": "0.1.2",
"files": [ "files": [
"src", "src",
"dist", "dist",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@united-workforce/agent-hermes", "name": "@united-workforce/agent-hermes",
"version": "0.1.4", "version": "0.1.3",
"files": [ "files": [
"src", "src",
"dist", "dist",
+2 -7
View File
@@ -12,11 +12,7 @@ const OWN_VERSION = (
} }
).version; ).version;
/** Resolve hermes binary: `UWF_HERMES_BIN` override → default `"hermes"` via PATH. */ const HERMES_COMMAND = "hermes";
function resolveHermesCommand(): string {
const override = process.env.UWF_HERMES_BIN;
return override !== undefined && override !== "" ? override : "hermes";
}
const PROTOCOL_VERSION = 1; const PROTOCOL_VERSION = 1;
type JsonRpcResponse = { type JsonRpcResponse = {
@@ -275,8 +271,7 @@ export class HermesAcpClient {
return; return;
} }
const hermesCommand = resolveHermesCommand(); const child = spawn(HERMES_COMMAND, ["acp"], {
const child = spawn(hermesCommand, ["acp"], {
env: process.env, env: process.env,
shell: false, shell: false,
stdio: ["pipe", "pipe", "pipe"], stdio: ["pipe", "pipe", "pipe"],
@@ -225,34 +225,4 @@ describe("buildOutputFormatInstruction", () => {
const result = buildOutputFormatInstruction({}); const result = buildOutputFormatInstruction({});
expect(result).toContain("Focus exclusively on YOUR role"); 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", "name": "@united-workforce/util-agent",
"version": "0.1.1", "version": "0.1.0",
"files": [ "files": [
"src", "src",
"dist", "dist",
@@ -74,10 +74,6 @@ function collectObjectSchemas(schema: JSONSchema): JSONSchema[] {
} }
function resolvePropertySchema(prop: JSONSchema): JSONSchema { function resolvePropertySchema(prop: JSONSchema): JSONSchema {
if (prop.const !== undefined) {
return prop;
}
if (Array.isArray(prop.enum) && prop.enum.length > 0) { if (Array.isArray(prop.enum) && prop.enum.length > 0) {
return prop; return prop;
} }
@@ -117,11 +113,6 @@ function buildPropertyExampleLine(prop: SchemaProperty): string {
commentParts.push("required"); 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) { if (Array.isArray(resolved.enum) && resolved.enum.length > 0) {
const enumValues = resolved.enum.map((v) => String(v)); const enumValues = resolved.enum.map((v) => String(v));
commentParts.push(...enumValues); commentParts.push(...enumValues);
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@united-workforce/util", "name": "@united-workforce/util",
"version": "0.1.4", "version": "0.1.3",
"files": [ "files": [
"src", "src",
"dist", "dist",