Merge pull request 'fix: PR #81 review follow-ups (closes #83)' (#84) from fix/pr81-review-followups into main
This commit was merged in pull request #84.
This commit is contained in:
@@ -193,15 +193,14 @@ export type PartitionedMessage = {
|
||||
* Extract display fields from a WorkflowMessage-shaped object.
|
||||
* `role` and `content` are used for header/body; `meta` is serialized as YAML frontmatter.
|
||||
*/
|
||||
export function partitionWorkflowMessage(msg: Record<string, unknown>): PartitionedMessage {
|
||||
const roleStr = typeof msg.role === "string" ? msg.role : "?";
|
||||
const contentRaw = msg.content;
|
||||
const contentBody =
|
||||
contentRaw === undefined || contentRaw === null
|
||||
? ""
|
||||
: typeof contentRaw === "string"
|
||||
? contentRaw
|
||||
: JSON.stringify(contentRaw);
|
||||
export function partitionWorkflowMessage(msg: {
|
||||
role: string;
|
||||
content: string;
|
||||
meta: unknown;
|
||||
timestamp: number;
|
||||
}): PartitionedMessage {
|
||||
const roleStr = msg.role;
|
||||
const contentBody = msg.content;
|
||||
const meta: Record<string, unknown> =
|
||||
msg.meta !== null && msg.meta !== undefined && typeof msg.meta === "object"
|
||||
? (msg.meta as Record<string, unknown>)
|
||||
@@ -213,9 +212,7 @@ export function partitionWorkflowMessage(msg: Record<string, unknown>): Partitio
|
||||
* One role round as plain text: header line, YAML frontmatter (meta only), body (content).
|
||||
*/
|
||||
export function formatThreadRoundBlock(row: ThreadRoundRow): string {
|
||||
const { roleStr, contentBody, meta } = partitionWorkflowMessage(
|
||||
row.message as unknown as Record<string, unknown>,
|
||||
);
|
||||
const { roleStr, contentBody, meta } = partitionWorkflowMessage(row.message);
|
||||
const yamlBlock =
|
||||
Object.keys(meta).length === 0 ? "{}\n" : `${stringify(meta, { lineWidth: 100 })}\n`;
|
||||
return (
|
||||
@@ -257,9 +254,7 @@ export function buildThreadCommandOutput(
|
||||
continue;
|
||||
}
|
||||
if (picked.length === 0) {
|
||||
const { roleStr, contentBody, meta } = partitionWorkflowMessage(
|
||||
row.message as unknown as Record<string, unknown>,
|
||||
);
|
||||
const { roleStr, contentBody, meta } = partitionWorkflowMessage(row.message);
|
||||
const yamlBlock =
|
||||
Object.keys(meta).length === 0 ? "{}\n" : `${stringify(meta, { lineWidth: 100 })}\n`;
|
||||
const header =
|
||||
|
||||
@@ -3,8 +3,7 @@ import { parse } from "yaml";
|
||||
import type { Result } from "./result.js";
|
||||
import { err, ok } from "./result.js";
|
||||
import type { NerveConfig, ReflexConfig, SenseConfig, WorkflowConfig } from "./types.js";
|
||||
|
||||
const DEFAULT_ENGINE_MAX_ROUNDS = 100;
|
||||
import { DEFAULT_ENGINE_MAX_ROUNDS } from "./types.js";
|
||||
|
||||
const DURATION_RE = /^(\d+)([smh])$/;
|
||||
|
||||
|
||||
@@ -18,17 +18,10 @@ export type {
|
||||
WorkflowDefinition,
|
||||
SenseResult,
|
||||
} from "./types.js";
|
||||
export { START, END } from "./types.js";
|
||||
export { START, END, DEFAULT_ENGINE_MAX_ROUNDS } from "./types.js";
|
||||
export type { Result } from "./result.js";
|
||||
export { ok, err } from "./result.js";
|
||||
export { parseNerveConfig } from "./config.js";
|
||||
|
||||
export function parseWorkflowField(field: string): { name: string; maxRounds: number; prompt: string } {
|
||||
const [name, rounds, ...rest] = field.split("|");
|
||||
const prompt = rest.join("|");
|
||||
const maxRounds = parseInt(rounds, 10);
|
||||
return { name: name ?? "", maxRounds, prompt };
|
||||
}
|
||||
|
||||
export type { ParsedSenseWorkflowDirective, SenseComputeRoute } from "./sense-workflow-directive.js";
|
||||
export { parseSenseWorkflowDirective, routeSenseComputeOutput } from "./sense-workflow-directive.js";
|
||||
|
||||
@@ -61,6 +61,9 @@ export const END = "__end__" as const;
|
||||
export type START = typeof START;
|
||||
export type END = typeof END;
|
||||
|
||||
/** Engine-wide fallback for max moderator rounds when not specified in config. */
|
||||
export const DEFAULT_ENGINE_MAX_ROUNDS = 100;
|
||||
|
||||
/** A single message in the workflow conversation chain (runtime, type-erased). */
|
||||
export type WorkflowMessage = {
|
||||
role: string;
|
||||
|
||||
@@ -147,14 +147,14 @@ export type LogStore = {
|
||||
runId: string,
|
||||
) => Array<{ role: string; content: string; meta: unknown; timestamp: number }>;
|
||||
/**
|
||||
* Count role command events for a run (excludes `thread_start` and invalid payloads).
|
||||
* Count role command events for a run (excludes `thread_start`/`__start__` messages and invalid payloads).
|
||||
* Round indices for {@link getThreadRounds} are 1..count in chronological order.
|
||||
*/
|
||||
getThreadRoundCount: (runId: string) => number;
|
||||
/**
|
||||
* Role rounds for agent-oriented retrieval: each row is one `thread_command_event`
|
||||
* whose JSON `type` is not `thread_start`, with `round` from ROW_NUMBER() OVER (ORDER BY id ASC).
|
||||
* No schema migration — numbering is computed in SQL.
|
||||
* Role rounds for agent-oriented retrieval: each row is one `thread_command_event` or
|
||||
* `thread_workflow_message` whose JSON `type` is not `thread_start` and `role` is not `__start__`,
|
||||
* with `round` from ROW_NUMBER() OVER (ORDER BY id ASC). No schema migration — numbering is computed in SQL.
|
||||
*/
|
||||
getThreadRounds: (runId: string, params: GetThreadRoundsParams) => ThreadRoundRow[];
|
||||
/**
|
||||
@@ -324,7 +324,8 @@ export function createLogStore(dbPath: string): LogStore {
|
||||
`SELECT COUNT(*) AS c FROM logs
|
||||
WHERE source = 'workflow' AND type IN ('thread_command_event', 'thread_workflow_message') AND ref_id = ?
|
||||
AND payload IS NOT NULL AND json_valid(payload) = 1
|
||||
AND COALESCE(json_extract(payload, '$.type'), '') != 'thread_start'`,
|
||||
AND COALESCE(json_extract(payload, '$.type'), '') != 'thread_start'
|
||||
AND COALESCE(json_extract(payload, '$.role'), '') != '__start__'`,
|
||||
);
|
||||
|
||||
const getThreadRoundsStmt = sqlite.prepare(
|
||||
@@ -335,6 +336,7 @@ export function createLogStore(dbPath: string): LogStore {
|
||||
WHERE source = 'workflow' AND type IN ('thread_command_event', 'thread_workflow_message') AND ref_id = @runId
|
||||
AND payload IS NOT NULL AND json_valid(payload) = 1
|
||||
AND COALESCE(json_extract(payload, '$.type'), '') != 'thread_start'
|
||||
AND COALESCE(json_extract(payload, '$.role'), '') != '__start__'
|
||||
)
|
||||
SELECT id, ts, payload, rn FROM numbered
|
||||
WHERE (@before = 0 OR rn < @before)
|
||||
|
||||
@@ -130,6 +130,15 @@ async function runThread(
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof result.content !== "string") {
|
||||
sendWorkflowError(runId, `Role "${nextRole}" returned non-string content`);
|
||||
return;
|
||||
}
|
||||
if (result.meta === null || typeof result.meta !== "object" || Array.isArray(result.meta)) {
|
||||
sendWorkflowError(runId, `Role "${nextRole}" returned invalid meta (must be a plain object)`);
|
||||
return;
|
||||
}
|
||||
|
||||
const message: WorkflowMessage = {
|
||||
role: nextRole,
|
||||
content: result.content,
|
||||
|
||||
Reference in New Issue
Block a user