Skip to content

feat: web harness improvements - #151

Merged
sergiofilhowz merged 1 commit into
mainfrom
feat/web-harness-improvements
May 18, 2026
Merged

feat: web harness improvements#151
sergiofilhowz merged 1 commit into
mainfrom
feat/web-harness-improvements

Conversation

@sergiofilhowz

@sergiofilhowz sergiofilhowz commented May 18, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Release Notes

  • New Features

    • Added visual "thinking" indicator that displays during agent processing
    • Mode-specific system prompts now adjust agent behavior for plan, ask, and agent modes
    • Function references now display as interactive pills in messages
  • Bug Fixes

    • Improved handling of empty function parameters in message display
    • Fixed streaming state transitions to prevent unintended message merging
  • Documentation

    • Enhanced error messages for authentication and credential validation

Review Change Stack

@vercel

vercel Bot commented May 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment May 18, 2026 0:43am

Request Review

@sergiofilhowz
sergiofilhowz marked this pull request as ready for review May 18, 2026 12:43
@github-actions

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 26 skipped (no docs/).

Layer Result
structure
vale
ai

Three for three. Nicely done.

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR transfers system-prompt construction from the console to the harness and extends it with mode-specific prefixes. It clarifies turn boundaries via explicit assistant-end events and defensive message streaming logic, adds a thinking indicator UI, and improves empty value rendering in function calls.

Changes

Mode-aware System Prompts and Message Boundary Handling

Layer / File(s) Summary
Mode type and system-prompt generation contract
harness-node/src/turn-orchestrator/system-prompt.ts
Mode union type ('plan' | 'ask' | 'agent') and MODE_PARAGRAPHS dispatch enable mode-specific system-prompt prefixes. Preamble extends to teach @fn(<function_id>) syntax for user text rendering. buildSystemPrompt() signature updated to accept optional mode parameter, prepending the selected mode paragraph ahead of identity preamble when override is unset.
Mode threading through harness orchestration
harness-node/src/turn-orchestrator/run-start.ts, harness-node/src/turn-orchestrator/states/provisioning.ts
Run request persists mode field derived from payload. Provisioning derives mode via new asMode helper and passes it to buildSystemPrompt, making system-prompt contents mode-aware.
System-prompt mode and assembly tests
harness-node/tests/turn-orchestrator/system-prompt.test.ts
Coverage added for mode-specific paragraphs (plan, ask, agent), preamble function-reference syntax, skill ordering, override precedence, and mode/preamble/cwd/skill ordering sequence.
Backend system-prompt ownership transfer and mode support
console/web/src/lib/backend/real.ts
resolveRunParams() simplified to return only { provider, model }, removing system-prompt generation responsibility. Backend now sends mode instead of system_prompt in run::start payload, establishing harness as system-prompt owner.
Turn boundary event translation for assistant-end
console/web/src/lib/backend/translate.ts
translateAgentEvent distinguishes message_end from other no-ops: emits assistant-end event for assistant-role messages, maintaining per-turn boundary clarity in event stream.
Chat UI message boundary and thinking indicator
console/web/src/components/chat/ChatView.tsx, console/web/src/components/chat/MessageList.tsx
ChatView adds defensive boundaries: proactively patches in-flight assistant when fcall-start arrives, clears buffers on assistant-end to prevent cross-turn merging. Computes isThinking flag from streaming state and message role, wired to MessageList which renders a thinking shimmer when true.
Function-call empty value handling
console/web/src/components/chat/FunctionCallMessage.tsx
ValuePane adds isEmptyValue helper classifying null, undefined, empty strings/arrays/objects as empty, rendering compact "· empty" header instead of primitive/JSON for those inputs.
Supporting implementation and formatting updates
harness-node/src/provider-anthropic/auth.ts, harness-node/src/provider-anthropic/stream.ts, harness-node/src/turn-orchestrator/states/functions.ts, harness-node/src/turn-orchestrator/transitions.ts
Anthropic modules normalize formatting and add debug logging for request headers/body. Function orchestration launches persistence as background promise before event emission, then awaits for ordering. Transitions orchestrator reformatted without behavioral change.

🎯 3 (Moderate) | ⏱️ ~25 minutes

A rabbit hops through harness and console,

System prompts now mode-aware and functional calls spun,

Message boundaries dance, thinking shimmer aglow,

Empty values whisper "·" as they flow! 🐰✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and generic, using the broad term 'improvements' without specifying which improvements or the main focus of the changeset. Provide a more specific title that highlights the primary change, such as 'feat: add mode-specific system prompts and thinking indicator' or 'feat: move system-prompt generation to harness'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/web-harness-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
harness-node/src/turn-orchestrator/states/provisioning.ts (1)

9-11: ⚡ Quick win

Centralize mode validation to prevent drift.

asMode duplicates the same mode guard logic already present in system-prompt.ts. If modes change later, these checks can silently diverge. Export a single validator and reuse it here.

Suggested refactor
- function asMode(value: unknown): Mode | null {
-   return value === 'plan' || value === 'ask' || value === 'agent' ? value : null;
- }
+// system-prompt.ts
+export function isMode(value: unknown): value is Mode {
+  return value === 'plan' || value === 'ask' || value === 'agent'
+}
- import { type DefaultSkillBody, type Mode, buildSystemPrompt, defaultSkillBody } from '../system-prompt.js';
+ import { type DefaultSkillBody, buildSystemPrompt, defaultSkillBody, isMode } from '../system-prompt.js';

- const mode = asMode(request.mode);
+ const mode = isMode(request.mode) ? request.mode : null;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@harness-node/src/turn-orchestrator/states/provisioning.ts` around lines 9 -
11, Replace the duplicated mode-guard in provisioning.ts by importing and
reusing the centralized validator from system-prompt.ts: export the canonical
mode validator (e.g., isMode or parseMode) from system-prompt.ts and then change
the local asMode function in provisioning.ts to call that exported validator (or
remove asMode and directly use the imported validator), ensuring all mode checks
reference the single shared function to avoid drift.
harness-node/src/turn-orchestrator/transitions.ts (1)

11-11: ⚡ Quick win

Use structured logging instead of console.log for production observability.

The console.log statement should use a proper logger (similar to the logger used in stream.ts) for structured logging, appropriate log levels, and better observability in production environments.

📊 Proposed improvement: Import and use logger

Add logger import:

+import { logger } from '../runtime/otel.js'
 import type { ISdk } from '../runtime/iii.js'

Replace console.log:

 export async function step(iii: ISdk, cfg: TurnOrchestratorConfig, rec: TurnStateRecord): Promise<void> {
-  console.log('step transition from', rec.state)
+  logger.debug('step transition', { from: rec.state })
   switch (rec.state) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@harness-node/src/turn-orchestrator/transitions.ts` at line 11, Replace the
console.log in transitions.ts with the project's structured logger: import the
same logger used in stream.ts (e.g., `import { logger } from '...stream'` or the
shared logger module) and change the call `console.log('step transition from',
rec.state)` to a structured log like `logger.info({ event: 'step_transition',
fromState: rec.state, recordId: rec.id })` (or use `logger.debug` if lower
verbosity is desired); ensure the import is added at top and any payload
includes relevant fields (rec.state and an identifier) for observability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@harness-node/src/provider-anthropic/stream.ts`:
- Around line 49-50: Remove the two console.log calls that print headers and
body (they leak authHeaderFor(cfg) and message content); instead, delete those
lines in stream.ts and, if diagnostic info is required, use the existing logger
(imported as logger) and log non-sensitive fields only or redact authorization
and prompt/message content before logging. Ensure references to headers, body,
and authHeaderFor(cfg) are not directly printed to stdout.

In `@harness-node/src/turn-orchestrator/states/functions.ts`:
- Around line 94-99: The current code starts persistence.saveExecutedCalls(...)
into savePromise then awaits emit(...), but if emit throws the savePromise is
never awaited; change the flow so savePromise is always awaited (either use
Promise.all([savePromise, emitPromise]) or wrap the emit call in try/finally and
await savePromise in the finally block) to ensure
persistence.saveExecutedCalls(iii, rec.session_id, results) is always awaited
and any errors are surfaced; adjust error handling so failures from both
emit(...) and persistence.saveExecutedCalls(...) are propagated or logged
appropriately.

---

Nitpick comments:
In `@harness-node/src/turn-orchestrator/states/provisioning.ts`:
- Around line 9-11: Replace the duplicated mode-guard in provisioning.ts by
importing and reusing the centralized validator from system-prompt.ts: export
the canonical mode validator (e.g., isMode or parseMode) from system-prompt.ts
and then change the local asMode function in provisioning.ts to call that
exported validator (or remove asMode and directly use the imported validator),
ensuring all mode checks reference the single shared function to avoid drift.

In `@harness-node/src/turn-orchestrator/transitions.ts`:
- Line 11: Replace the console.log in transitions.ts with the project's
structured logger: import the same logger used in stream.ts (e.g., `import {
logger } from '...stream'` or the shared logger module) and change the call
`console.log('step transition from', rec.state)` to a structured log like
`logger.info({ event: 'step_transition', fromState: rec.state, recordId: rec.id
})` (or use `logger.debug` if lower verbosity is desired); ensure the import is
added at top and any payload includes relevant fields (rec.state and an
identifier) for observability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 46c69c21-aed4-47d2-b5eb-38a13596edfa

📥 Commits

Reviewing files that changed from the base of the PR and between 58e0e05 and e21b276.

📒 Files selected for processing (13)
  • console/web/src/components/chat/ChatView.tsx
  • console/web/src/components/chat/FunctionCallMessage.tsx
  • console/web/src/components/chat/MessageList.tsx
  • console/web/src/lib/backend/real.ts
  • console/web/src/lib/backend/translate.ts
  • harness-node/src/provider-anthropic/auth.ts
  • harness-node/src/provider-anthropic/stream.ts
  • harness-node/src/turn-orchestrator/run-start.ts
  • harness-node/src/turn-orchestrator/states/functions.ts
  • harness-node/src/turn-orchestrator/states/provisioning.ts
  • harness-node/src/turn-orchestrator/system-prompt.ts
  • harness-node/src/turn-orchestrator/transitions.ts
  • harness-node/tests/turn-orchestrator/system-prompt.test.ts

Comment on lines +49 to +50
console.log('headers', headers)
console.log('body', body)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Remove debug logging that exposes credentials.

These console.log statements expose sensitive authentication headers and potentially sensitive prompt/message content. The headers object includes the authorization credential from authHeaderFor(cfg) (lines 42-47), and logging it to console risks leaking API keys in production logs.

Remove these debug statements or, if diagnostic logging is needed, use the existing logger (imported at line 7) with proper redaction of sensitive fields.

🔒 Proposed fix: Remove debug logging
-  console.log('headers', headers)
-  console.log('body', body)
-
   const ac = new AbortController()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log('headers', headers)
console.log('body', body)
const ac = new AbortController()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@harness-node/src/provider-anthropic/stream.ts` around lines 49 - 50, Remove
the two console.log calls that print headers and body (they leak
authHeaderFor(cfg) and message content); instead, delete those lines in
stream.ts and, if diagnostic info is required, use the existing logger (imported
as logger) and log non-sensitive fields only or redact authorization and
prompt/message content before logging. Ensure references to headers, body, and
authHeaderFor(cfg) are not directly printed to stdout.

Comment on lines +94 to +99
// Kick off persistence in parallel with the user-facing emit so the UI's
// fcall-end lands ~one trigger round-trip sooner. We still await both
// before the next iteration so ordering and durability are preserved.
const savePromise = persistence.saveExecutedCalls(iii, rec.session_id, results);
await emit(iii, rec.session_id, buildFunctionExecutionEnd(fc, result, is_error));
await savePromise;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Ensure savePromise is always awaited to prevent unhandled rejections.

If emit (line 98) throws an exception, the savePromise (line 97) is abandoned without being awaited. This can result in:

  1. Unhandled promise rejections if the save operation fails
  2. Loss of error information from the persistence layer
  3. Potential Node.js process warnings or crashes in strict rejection mode

Use Promise.all or wrap in try/finally to guarantee the save promise is awaited even if emit fails.

🛡️ Proposed fix: Ensure both operations are awaited
-    const savePromise = persistence.saveExecutedCalls(iii, rec.session_id, results);
-    await emit(iii, rec.session_id, buildFunctionExecutionEnd(fc, result, is_error));
-    await savePromise;
+    // Kick off persistence in parallel with the user-facing emit so the UI's
+    // fcall-end lands ~one trigger round-trip sooner. We still await both
+    // before the next iteration so ordering and durability are preserved.
+    await Promise.all([
+      persistence.saveExecutedCalls(iii, rec.session_id, results),
+      emit(iii, rec.session_id, buildFunctionExecutionEnd(fc, result, is_error)),
+    ]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@harness-node/src/turn-orchestrator/states/functions.ts` around lines 94 - 99,
The current code starts persistence.saveExecutedCalls(...) into savePromise then
awaits emit(...), but if emit throws the savePromise is never awaited; change
the flow so savePromise is always awaited (either use Promise.all([savePromise,
emitPromise]) or wrap the emit call in try/finally and await savePromise in the
finally block) to ensure persistence.saveExecutedCalls(iii, rec.session_id,
results) is always awaited and any errors are surfaced; adjust error handling so
failures from both emit(...) and persistence.saveExecutedCalls(...) are
propagated or logged appropriately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant