Repository navigation
feat(harness): @jambonz/sdk/harness skeleton custom harness - #25
Merged
Merged
Conversation
…e agent verb
createHarness() implements the jambonz harness WebSocket protocol
(harness.jambonz.org, protocol 1) and works as a pass-through to an
OpenAI-compatible chat model; developers add code only through hooks
(onSessionStart, beforeModel, tools, checkSentence, afterTurn, onEvent,
onSessionEnd).
- typed protocol messages for both directions
- bearer-key auth on upgrade, subprotocol check, close 4000 on an
unsupported protocol version, GET /health
- history, streaming chunks, sentence checks, turn:cancel aborts the
model stream, barge-in trims history to what was heard
- tool loop for own tools and the agent's Studio tools (tool:call)
- greeting turn, default silence/no_input policy, A.13 turn record
- resume on session:start {resumed: true} within 10s
- examples/harness and a README section
- tests over real WebSockets with a fake jambonz client and a fake
OpenAI-compatible streaming server
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ons types - label on the llm/s2s verbs: with no auth, the account's speech-to-speech credential with that label (schema 0.4.33) - paxaOptions on the recognizer, which the schema already had - schema-drift tests pass again (156) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The schema-drift test failed after the 0.4.36 bump: the schema's rime_s2s verb had no TypeScript counterpart. Added like gptlive_s2s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
@jambonz/sdk/harness: a skeleton custom harness for theagentverb (llm.vendor: "harness"), per AGENT-ENGINES-DESIGN §6 and Appendix A.createHarness()speaks the whole harness WebSocket protocol (harness.jambonz.org, protocol 1) and works unchanged as a pass-through to an OpenAI-compatible chat model; a developer adds code only through hooks.API
ctx:callSid,session(the session:start message),state(Map),history(user/assistant/tool messages),say(text, {interrupt, interruptible})→ reply id,command(name, args)→Promise<{ok, error?}>,callTool(name, args)(Studio tool viatool:call),record(field, value),log(pino child withcall_sid).Also exported: every protocol message type for both directions (
SessionStartMessage,TurnStartMessage,ReplyChunkMessage,TurnRecord,HarnessEvent, ...),createModelClient,SentenceSplitter.Built-in behaviour: history; chunks passed through as they arrive (sentence-by-sentence synthesized chunks when
checkSentenceis set);turn:cancel(and a supersedingturn:start) aborts the model stream and silences the turn; barge-in trims history touser_interruption.spoken; tool loop over own tools andsession:start.tools(Studio tools viatool:call/tool:result), with a cancelled turn's pending tool calls answered so history stays valid; greeting turn; silence/no_input policy (ask once, then goodbye andhangupafter the goodbye is spoken; override withonEvent.silence); A.13 turn record on everyreply:done(route, steps with timings for beforeModel/model/tool/output_check, model_calls with tokens viastream_options.include_usage, own_tools, ctx.record fields; truncated with a warning over 16 KB); resume onsession:start {resumed: true}within 10 s; close 4000 on an unsupported protocol version; unknown message types ignored;GET /health.Failures are logged with
call_sid/turn_id: rejected upgrades (401/400 with reason), model errors (alsoturn_record.error, plus a spokenerrorReply), hook exceptions, failed commands and tools,errorevents from jambonz, socket drops.New dependency:
pino^9 (Node 18 compatible). The model client uses globalfetch(noopenaidependency).How tested
typescript/test/harness.test.ts(22 tests) runs the real server over real WebSockets against a fake jambonz client and a fake OpenAI-compatible SSE server: greeting turn and chunk pass-through, fixed greeting, speech turn history, turn:cancel aborts the stream plus barge-in trimming, beforeModel routing / reply without model, Studio tool round trip, Studio tool error, cancel during a tool call, developer tool + own_tools, checkSentence false stops / string replaces, turn_record fields with afterTurn, model failure, commands from onEvent, default silence and no_input policies, onEvent.silence override, unknown types ignored, protocol 4000, auth rejected/accepted, subprotocol required, sentence splitter.npm run typecheck,npm test(155 passing) andnpm run buildpass.npm run lintfails onmainalready (eslint is neither installed nor configured; CI runs typecheck + test only), so it was not used.The example was also packed against the built SDK, typechecked with
module: Node16, and driven end to end (greeting → routed outage turn → own tool → sentence replacement → turn record).Run the example
Then add a Harness LLM credential in jambonz with URL
ws(s)://host:8080and API key =HARNESS_API_KEY, and use it from anagentverb withllm.vendor: "harness". Seeexamples/harness/README.md.Not implemented
speech:start/transcriptare received and ignored; no hook exposes them yet.application_update(e.g.inject_context,generate_reply) has no default behaviour; it reachesonEvent.application_updateonly.🤖 Generated with Claude Code