August Changelog Docs Sync (#1009)
* chore(docs): Sync Docs with latest Changelog features * chore: nit on sentence style * chore: simplifying language. --------- Co-authored-by: ajspig <dragon@monstercode.com>
This commit is contained in:
parent
81d8409b8c
commit
57ae7ef4d8
|
|
@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
### Added
|
||||
|
||||
- Session allowlist on the Dialectic and representation via a constrained `filters` body on `POST /peers/{peer_id}/chat` and `/representation`, supporting only the `session_id` key (a session id, a bare list, or `{"in": [...]}`). Unsupported keys and shapes are rejected with 422 rather than silently ignored, it composes with `session_id` (which must be included in the allowlist when both are given), and it is capped at 1,000 sessions per request. Enforcement is uniform and fail-closed at every recall chokepoint: scoped conclusion recall is restricted to `level == "explicit"` (dream-derived conclusions carry a single `session_name` but are synthesized across all sessions, so that stamp can't be scoped on), `get_reasoning_chain` is unavailable under an allowlist, and an empty allowlist short-circuits to empty results everywhere. Workspace keys pass the allowlist as-given; peer-scoped JWTs must be an active member of every allowlisted session (403 otherwise) (#882)
|
||||
- Session allowlist on the Dialectic and representation via a constrained `filters` body on `POST /peers/{peer_id}/chat` and `/representation`, supporting only the `session_id` key (a session id, a bare list, or `{"in": [...]}`). Unsupported keys and shapes are rejected with 422 rather than silently ignored, it composes with `session_id` (which must be included in the allowlist when both are given), and it is capped at 1,000 sessions per request. Enforcement is uniform and fail-closed at every recall chokepoint: scoped conclusion recall is restricted to `level == "explicit"` (dream-derived conclusions carry a single `session_name` but are synthesized across all sessions, so that stamp can't be scoped on), `get_reasoning_chain` is unavailable under an allowlist, and an empty allowlist short-circuits to empty results everywhere. Workspace keys pass the allowlist as-given; peer-scoped JWTs must be an active member of every allowlisted session (401 otherwise) (#882)
|
||||
- Bare-list membership sugar in the filter DSL: `{"session_id": ["s1", "s2"]}` is now shorthand for `{"session_id": {"in": [...]}}` on regular columns generically. JSONB metadata columns are excluded and keep containment semantics. Strictly additive, since a bare list on a regular column previously compiled to a type-mismatched equality that matched nothing (#881)
|
||||
- Optional structured outputs on the Dialectic: `response_format` (a JSON Schema with root type `object`) on peer chat makes `content` a JSON string conforming to that schema. Only a conservative subset of JSON Schema is supported, with DoS guards and non-recursive `$ref` support (#896)
|
||||
- Combined tool calling and structured output in the LLM transport layer, with per-backend request shaping: OpenAI routes tool-carrying structured requests through `create()` with an explicit `json_schema` response format (`parse()` 500s on non-strict function tools), Anthropic skips the `{` JSON prefill when tools are present so `tool_use` blocks stay reachable, and Gemini injects a schema instruction into the final turn instead of using native `response_schema` (rejected alongside function calling before Gemini 3). All backends skip structured-output parsing on tool-call turns, which carry no consumable content (#907)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Welcome to the Honcho changelog! This section documents all notable changes to t
|
|||
<Update label="v3.0.12 (Current)">
|
||||
### Added
|
||||
|
||||
- Session allowlist on the Dialectic and representation via a constrained `filters` body on `POST /peers/{peer_id}/chat` and `/representation`, supporting only the `session_id` key (a session id, a bare list, or `{"in": [...]}`). Unsupported keys and shapes are rejected with 422 rather than silently ignored, it composes with `session_id` (which must be included in the allowlist when both are given), and it is capped at 1,000 sessions per request. Enforcement is uniform and fail-closed at every recall chokepoint: scoped conclusion recall is restricted to `level == "explicit"` (dream-derived conclusions carry a single `session_name` but are synthesized across all sessions, so that stamp can't be scoped on), `get_reasoning_chain` is unavailable under an allowlist, and an empty allowlist short-circuits to empty results everywhere. Workspace keys pass the allowlist as-given; peer-scoped JWTs must be an active member of every allowlisted session (403 otherwise) (#882)
|
||||
- Session allowlist on the Dialectic and representation via a constrained `filters` body on `POST /peers/{peer_id}/chat` and `/representation`, supporting only the `session_id` key (a session id, a bare list, or `{"in": [...]}`). Unsupported keys and shapes are rejected with 422 rather than silently ignored, it composes with `session_id` (which must be included in the allowlist when both are given), and it is capped at 1,000 sessions per request. Enforcement is uniform and fail-closed at every recall chokepoint: scoped conclusion recall is restricted to `level == "explicit"` (dream-derived conclusions carry a single `session_name` but are synthesized across all sessions, so that stamp can't be scoped on), `get_reasoning_chain` is unavailable under an allowlist, and an empty allowlist short-circuits to empty results everywhere. Workspace keys pass the allowlist as-given; peer-scoped JWTs must be an active member of every allowlisted session (401 otherwise) (#882)
|
||||
- Bare-list membership sugar in the filter DSL: `{"session_id": ["s1", "s2"]}` is now shorthand for `{"session_id": {"in": [...]}}` on regular columns generically. JSONB metadata columns are excluded and keep containment semantics. Strictly additive, since a bare list on a regular column previously compiled to a type-mismatched equality that matched nothing (#881)
|
||||
- Optional structured outputs on the Dialectic: `response_format` (a JSON Schema with root type `object`) on peer chat makes `content` a JSON string conforming to that schema. Only a conservative subset of JSON Schema is supported, with DoS guards and non-recursive `$ref` support (#896)
|
||||
- Combined tool calling and structured output in the LLM transport layer, with per-backend request shaping: OpenAI routes tool-carrying structured requests through `create()` with an explicit `json_schema` response format (`parse()` 500s on non-strict function tools), Anthropic skips the `{` JSON prefill when tools are present so `tool_use` blocks stay reachable, and Gemini injects a schema instruction into the final turn instead of using native `response_schema` (rejected alongside function calling before Gemini 3). All backends skip structured-output parsing on tool-call turns, which carry no consumable content (#907)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
"v3/documentation/features/advanced/representation-scopes",
|
||||
"v3/documentation/features/advanced/dreaming",
|
||||
"v3/documentation/features/advanced/queue-status",
|
||||
"v3/documentation/features/advanced/webhooks",
|
||||
"v3/documentation/features/advanced/search",
|
||||
"v3/documentation/features/advanced/using-filters",
|
||||
"v3/documentation/features/advanced/structured-outputs",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ You can retrieve a subset of conclusions from a peer's representation using `rep
|
|||
alice_rep = session.representation("alice")
|
||||
|
||||
# Or via chat
|
||||
response = alice.chat("What are Alice's main interests?", session_id=session.id)
|
||||
response = alice.chat("What are Alice's main interests?", session=session.id)
|
||||
```
|
||||
|
||||
This is sufficient for most applications—Honcho reasons over every message written to the peer, storing conclusions that any part of your system can retrieve.
|
||||
|
|
@ -160,13 +160,13 @@ The `target` parameter also works with the chat endpoint:
|
|||
# Query using conclusions from Honcho's representation (across all sessions)
|
||||
honcho_answer = alice.chat(
|
||||
"What did Bob say about breakfast?",
|
||||
session_id=session.id
|
||||
session=session.id
|
||||
)
|
||||
|
||||
# Query using conclusions from Alice's representation of Bob (from Alice's sessions only)
|
||||
alice_answer = alice.chat(
|
||||
"What did Bob say about breakfast?",
|
||||
session_id=session.id,
|
||||
session=session.id,
|
||||
target="bob"
|
||||
)
|
||||
```
|
||||
|
|
@ -175,13 +175,13 @@ alice_answer = alice.chat(
|
|||
// Query using conclusions from Honcho's representation (across all sessions)
|
||||
const honchoAnswer = await alice.chat(
|
||||
"What did Bob say about breakfast?",
|
||||
{ sessionId: session.id }
|
||||
{ session: session.id }
|
||||
);
|
||||
|
||||
// Query using conclusions from Alice's representation of Bob (from Alice's sessions only)
|
||||
const aliceAnswer = await alice.chat(
|
||||
"What did Bob say about breakfast?",
|
||||
{ sessionId: session.id, target: "bob" }
|
||||
{ session: session.id, target: "bob" }
|
||||
);
|
||||
```
|
||||
</CodeGroup>
|
||||
|
|
@ -225,7 +225,7 @@ This architecture enables:
|
|||
|
||||
## Semantic Search Parameters
|
||||
|
||||
Both `representation()` and `chat()` support semantic filtering to retrieve a subset of relevant conclusions. You can optionally filter by session to retrieve only conclusions from specific session context:
|
||||
Both `representation()` and `chat()` support semantic filtering to retrieve a subset of relevant conclusions. You can optionally filter by session — pass `session` to scope to a single session, or use the REST-only [session allowlist](/v3/documentation/features/advanced/using-filters#scoping-recall-to-sessions) to scope to a set of sessions:
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
|
|
|
|||
|
|
@ -304,6 +304,33 @@ sessions = honcho.sessions(filters={
|
|||
|
||||
### List Membership
|
||||
|
||||
A bare list is shorthand for `in`, so `{"peer_id": ["alice", "bob"]}` and
|
||||
`{"peer_id": {"in": ["alice", "bob"]}}` are equivalent:
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
# Shorthand: a bare list means "any of these"
|
||||
messages = session.messages(filters={
|
||||
"peer_id": ["alice", "bob", "charlie"]
|
||||
})
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
(async () => {
|
||||
// Shorthand: a bare list means "any of these"
|
||||
const messages = await session.messages({
|
||||
filters: { peer_id: ["alice", "bob", "charlie"] }
|
||||
});
|
||||
})();
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Warning>
|
||||
Bare lists behave differently inside metadata — use `{"in": [...]}` there for OR matching.
|
||||
</Warning>
|
||||
|
||||
The explicit form, plus the other comparison operators:
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
# Find messages from specific peers in a session
|
||||
|
|
@ -673,6 +700,93 @@ bob_explicit = peer.conclusions_of("bob").list(filters={"level": "explicit"})
|
|||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Scoping Recall to Sessions
|
||||
|
||||
The [chat endpoint](/v3/documentation/features/chat) and the representation
|
||||
endpoint accept a `filters` body too, but a deliberately narrow one: it defines
|
||||
a **session allowlist**, restricting what the request can recall to the sessions
|
||||
you name — conclusions on both endpoints, and on chat the messages the agent
|
||||
reads as well.
|
||||
|
||||
This is how you scope recall to more than one session. The `session_id`
|
||||
parameter pins a request to exactly one session; an allowlist accepts a set.
|
||||
|
||||
Only the `session_id` key is supported here, in three shapes:
|
||||
|
||||
```json
|
||||
{"filters": {"session_id": "support-chat-1"}}
|
||||
{"filters": {"session_id": ["support-chat-1", "support-chat-2"]}}
|
||||
{"filters": {"session_id": {"in": ["support-chat-1", "support-chat-2"]}}}
|
||||
```
|
||||
|
||||
<CodeGroup>
|
||||
```bash Chat
|
||||
curl -X POST "$HONCHO_URL/v3/workspaces/my-app/peers/user-123/chat" \
|
||||
-H "Authorization: Bearer $HONCHO_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"query": "What did the user ask about billing?",
|
||||
"filters": { "session_id": ["support-chat-1", "support-chat-2"] }
|
||||
}'
|
||||
```
|
||||
|
||||
```bash Representation
|
||||
curl -X POST "$HONCHO_URL/v3/workspaces/my-app/peers/user-123/representation" \
|
||||
-H "Authorization: Bearer $HONCHO_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"filters": { "session_id": ["support-chat-1", "support-chat-2"] }
|
||||
}'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Note>
|
||||
The session allowlist is REST-only today. The SDKs cover the single-session case
|
||||
with `session`, but do not yet expose the allowlist — call the endpoint directly
|
||||
when you need a set of sessions.
|
||||
</Note>
|
||||
|
||||
### Rules
|
||||
|
||||
Unlike the list endpoints above, this filter **fails closed**: an unrecognized
|
||||
key or shape is rejected with `422` rather than ignored, because a silently
|
||||
dropped filter here would widen recall instead of narrowing it.
|
||||
|
||||
| Rule | Behavior |
|
||||
|------|----------|
|
||||
| Any key other than `session_id` | `422` |
|
||||
| A shape other than a string, a list of strings, or `{"in": [...]}` | `422` |
|
||||
| More than 1,000 sessions | `422` |
|
||||
| `session_id` set alongside `filters` | The `session_id` must appear in the allowlist, else `422` |
|
||||
| An empty allowlist (`[]`) | Valid, and recalls nothing |
|
||||
| A peer-scoped key naming a session its peer isn't an active member of | `401` on chat — see below |
|
||||
|
||||
<Note>
|
||||
On chat, a peer-scoped key must be an active member of every session it names —
|
||||
the allowlist reaches message recall there — and the request is rejected with
|
||||
`401` otherwise. The representation endpoint runs no membership check: key scope
|
||||
already confines the caller to its own peer's representation, which an allowlist
|
||||
can only narrow.
|
||||
</Note>
|
||||
|
||||
### What Changes Under an Allowlist
|
||||
|
||||
Scoping recall by session narrows what the reasoning agent can draw on:
|
||||
|
||||
- **Only `explicit` conclusions are recalled.** Dream-derived conclusions
|
||||
(`deductive`, `inductive`) are synthesized across sessions, so they can't be
|
||||
attributed to one session and are excluded.
|
||||
- **Reasoning-chain traversal is unavailable**, since it walks into those
|
||||
derived conclusions.
|
||||
- **Message recall is restricted to the allowlisted sessions** across every
|
||||
search path — semantic, keyword, and date-range.
|
||||
|
||||
<Note>
|
||||
Because of this, an allowlisted request answers from directly-stated facts
|
||||
rather than higher-order inferences. If you want the full representation, omit
|
||||
`filters` and let the agent search everything.
|
||||
</Note>
|
||||
|
||||
## Error Handling
|
||||
|
||||
Handle filter errors gracefully:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,217 @@
|
|||
---
|
||||
title: 'Webhooks'
|
||||
description: 'Receive push notifications when Honcho finishes background work'
|
||||
icon: 'satellite-dish'
|
||||
---
|
||||
|
||||
Honcho's reasoning runs in the background, so a message you just created is not
|
||||
immediately reflected in the peer's representation. Instead of polling
|
||||
[queue status](/v3/documentation/features/advanced/queue-status), you can
|
||||
register a webhook endpoint and have Honcho notify you when the work it queued
|
||||
for a session has drained.
|
||||
|
||||
Webhooks are registered per workspace. Every event for that workspace is
|
||||
delivered to every endpoint registered on it.
|
||||
|
||||
## Registering an Endpoint
|
||||
|
||||
<CodeGroup>
|
||||
```bash Register
|
||||
curl -X POST "$HONCHO_URL/v3/workspaces/my-app/webhooks" \
|
||||
-H "Authorization: Bearer $HONCHO_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"url": "https://example.com/honcho/webhook"}'
|
||||
```
|
||||
|
||||
```bash List
|
||||
curl -X GET "$HONCHO_URL/v3/workspaces/my-app/webhooks" \
|
||||
-H "Authorization: Bearer $HONCHO_API_KEY"
|
||||
```
|
||||
|
||||
```bash Test
|
||||
curl -X GET "$HONCHO_URL/v3/workspaces/my-app/webhooks/test" \
|
||||
-H "Authorization: Bearer $HONCHO_API_KEY"
|
||||
```
|
||||
|
||||
```bash Delete
|
||||
curl -X DELETE "$HONCHO_URL/v3/workspaces/my-app/webhooks/$ENDPOINT_ID" \
|
||||
-H "Authorization: Bearer $HONCHO_API_KEY"
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Registration is get-or-create: a URL already registered on the workspace
|
||||
returns `200` with the existing endpoint, a new one returns `201`. The test
|
||||
route emits a `test.event` to every endpoint on the workspace, which is the
|
||||
quickest way to confirm your receiver and signature check work end to end.
|
||||
|
||||
Webhook routes accept an admin key or a workspace-scoped key for that
|
||||
workspace. Peer- and session-scoped keys cannot manage webhooks.
|
||||
|
||||
<Note>
|
||||
Webhook management is also available in the dashboard on the
|
||||
[Webhooks](https://app.honcho.dev/webhooks) page.
|
||||
</Note>
|
||||
|
||||
### URL Requirements
|
||||
|
||||
A webhook URL must be absolute and use `http` or `https`. URLs whose host is an
|
||||
IP literal in a private, loopback, link-local, reserved, multicast, or
|
||||
unspecified range are rejected with `422`.
|
||||
|
||||
<Warning>
|
||||
This check inspects IP literals only — hostnames are accepted without
|
||||
resolution. If you self-host, treat network-level egress controls, not this
|
||||
validation, as your defense against internal-address delivery.
|
||||
</Warning>
|
||||
|
||||
Each workspace can register up to `WEBHOOK_MAX_WORKSPACE_LIMIT` endpoints
|
||||
(default 10). Exceeding the limit returns `409`.
|
||||
|
||||
## Events
|
||||
|
||||
| Event | When it fires | `data` fields |
|
||||
|-------|---------------|---------------|
|
||||
| `queue.empty` | A unit of queued background work finished draining | `workspace_id`, `queue_type` (`representation` or `summary`), `session_id`, `observer`, `observed` |
|
||||
| `test.event` | You called `GET /webhooks/test` | `workspace_id` |
|
||||
|
||||
<Warning>
|
||||
`queue.empty` is scoped to a single unit of work — one task type for one
|
||||
session and observer/observed pair — not to the workspace as a whole. Other
|
||||
work may still be queued elsewhere in the workspace when it fires. A session
|
||||
whose messages produce both representation and summary work emits one event per
|
||||
task type.
|
||||
</Warning>
|
||||
|
||||
## Payload
|
||||
|
||||
Every delivery is a `POST` with a `Content-Type: application/json` body in this
|
||||
envelope:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "queue.empty",
|
||||
"data": {
|
||||
"workspace_id": "my-app",
|
||||
"queue_type": "representation",
|
||||
"session_id": "support-chat-1",
|
||||
"observer": "assistant",
|
||||
"observed": "user-123"
|
||||
},
|
||||
"timestamp": "2026-08-10T18:24:05.123456Z"
|
||||
}
|
||||
```
|
||||
|
||||
**`data` is event-specific — its keys differ by event type.** A `test.event`
|
||||
carries only `workspace_id`:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "test.event",
|
||||
"data": { "workspace_id": "my-app" },
|
||||
"timestamp": "2026-08-10T18:24:05.123456Z"
|
||||
}
|
||||
```
|
||||
|
||||
Within one event type, an optional field with no value is sent as an explicit
|
||||
`null` — on `queue.empty`, that's `session_id`, `observer`, and `observed` for
|
||||
work that isn't tied to a session or an observer pair. Across event types the key
|
||||
is simply absent.
|
||||
|
||||
Parse defensively: branch on `type` as the discriminator, treat every `data` key
|
||||
as optional rather than required, and tolerate new event types and new fields.
|
||||
A parser that requires the `queue.empty` keys on every event will break on a
|
||||
`test.event`.
|
||||
|
||||
## Verifying Signatures
|
||||
|
||||
Each delivery carries an `X-Honcho-Signature` header: the hex-encoded
|
||||
HMAC-SHA256 of the **raw request body**, keyed with your deployment's
|
||||
`WEBHOOK_SECRET`. Always compare with a constant-time function, and always sign
|
||||
the bytes you received — Honcho serializes the body compactly with sorted keys,
|
||||
so re-serializing your parsed JSON will not reliably reproduce it.
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
|
||||
def verify(raw_body: bytes, signature: str) -> bool:
|
||||
expected = hmac.new(
|
||||
os.environ["WEBHOOK_SECRET"].encode(),
|
||||
raw_body,
|
||||
hashlib.sha256,
|
||||
).hexdigest()
|
||||
return hmac.compare_digest(expected, signature)
|
||||
|
||||
# FastAPI — read the raw body, not a parsed model
|
||||
@app.post("/honcho/webhook")
|
||||
async def handle(request: Request):
|
||||
raw = await request.body()
|
||||
if not verify(raw, request.headers.get("X-Honcho-Signature", "")):
|
||||
raise HTTPException(status_code=401)
|
||||
event = json.loads(raw)
|
||||
...
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
import crypto from 'node:crypto';
|
||||
|
||||
function verify(rawBody: Buffer, signature: string): boolean {
|
||||
const expected = crypto
|
||||
.createHmac('sha256', process.env.WEBHOOK_SECRET!)
|
||||
.update(rawBody)
|
||||
.digest('hex');
|
||||
const a = Buffer.from(expected);
|
||||
const b = Buffer.from(signature);
|
||||
return a.length === b.length && crypto.timingSafeEqual(a, b);
|
||||
}
|
||||
|
||||
// Express — note express.raw(), not express.json()
|
||||
app.post('/honcho/webhook', express.raw({ type: 'application/json' }), (req, res) => {
|
||||
if (!verify(req.body, req.header('X-Honcho-Signature') ?? '')) {
|
||||
return res.sendStatus(401);
|
||||
}
|
||||
const event = JSON.parse(req.body.toString());
|
||||
res.sendStatus(200);
|
||||
});
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Delivery Semantics
|
||||
|
||||
Delivery is best-effort and fire-and-forget:
|
||||
|
||||
- Events fan out to all of the workspace's endpoints concurrently.
|
||||
- Each request has a 30-second timeout.
|
||||
- **There are no retries.** A non-2xx response, a timeout, or a connection
|
||||
error is logged on the server and the event is dropped.
|
||||
|
||||
Design your receiver accordingly: treat the event as a hint to re-read state
|
||||
from the API rather than as the state itself, and fall back to
|
||||
[queue status](/v3/documentation/features/advanced/queue-status) polling if you
|
||||
need a guarantee.
|
||||
|
||||
## Self-Hosting Requirements
|
||||
|
||||
<Warning>
|
||||
`WEBHOOK_SECRET` must be set, or nothing is delivered. Honcho signs every
|
||||
payload before sending it; with no secret configured, signing fails and the
|
||||
event is dropped after being logged. Registration still succeeds, so a missing
|
||||
secret looks like silence rather than an error.
|
||||
</Warning>
|
||||
|
||||
Webhook delivery is queued work handled by the deriver process, so a deriver
|
||||
worker must be running for events to be sent. See
|
||||
[Configuration](/v3/contributing/configuration#webhooks) for
|
||||
`WEBHOOK_SECRET` and `WEBHOOK_MAX_WORKSPACE_LIMIT`.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Queue Status" icon="list-check" href="/v3/documentation/features/advanced/queue-status">
|
||||
Poll background processing state instead of waiting for a push
|
||||
</Card>
|
||||
<Card title="Webhook API Reference" icon="code" href="/v3/api-reference/endpoint/webhooks/get-or-create-webhook-endpoint">
|
||||
Full request and response schemas for the webhook endpoints
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
|
@ -94,6 +94,27 @@ for await (const chunk of responseStream.iter_text()) {
|
|||
|
||||
Streaming is useful for displaying real-time responses in chat interfaces or when asking complex questions that require longer answers.
|
||||
|
||||
## Scoping to Sessions
|
||||
|
||||
By default the chat endpoint reasons over everything Honcho knows about the
|
||||
peer. Pass `session` (`session_id` on the REST body) to restrict it to one
|
||||
session:
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
answer = peer.chat("What did the user ask about?", session=session.id)
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
const answer = await peer.chat("What did the user ask about?", { session: session.id });
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
To scope a request to a *set* of sessions, use the session allowlist — a
|
||||
constrained `filters` body on the endpoint. See
|
||||
[Scoping Recall to Sessions](/v3/documentation/features/advanced/using-filters#scoping-recall-to-sessions)
|
||||
for the accepted shapes and for what an allowlist changes about the answer.
|
||||
|
||||
## Structured Outputs
|
||||
|
||||
When your application needs a machine-readable answer instead of prose, pass a schema as `response_format` and the answer is guaranteed to conform to it:
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ Scoped keys are authorized by their narrowest claim and never widen to the whole
|
|||
- A **peer-scoped** key acts on its own peer, plus **read-only** access to the sessions its peer is an active member of (context, summaries, peers, its own per-session config, search, and message reads). It cannot write to those sessions or act on other peers.
|
||||
- A **session-scoped** key is confined to its own session and cannot reach peer routes.
|
||||
- Peer- and session-scoped keys **must carry their parent workspace** — creating one without a workspace is rejected.
|
||||
- On the chat endpoint, a peer-scoped key can only name sessions its peer is an active member of — both the `session_id` and every session in a [session allowlist](/v3/documentation/features/advanced/using-filters#scoping-recall-to-sessions). Naming any other session returns `401`. Workspace and admin keys pass the allowlist through as given.
|
||||
|
||||
<Frame>
|
||||
<img src="/images/app-screenshots/api-keys.png" alt="API Key Management Dashboard" width="1200" height="800" loading="lazy" decoding="async" fetchpriority="low" />
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"url": "https://honcho.dev/",
|
||||
"email": "hello@plasticlabs.ai"
|
||||
},
|
||||
"version": "3.0.11"
|
||||
"version": "3.0.12"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
|
|
@ -2909,6 +2909,14 @@
|
|||
"title": "Session Id",
|
||||
"description": "ID of the session to scope the representation to"
|
||||
},
|
||||
"filters": {
|
||||
"anyOf": [
|
||||
{ "additionalProperties": true, "type": "object" },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"title": "Filters",
|
||||
"description": "Optional filters to scope recall. This endpoint supports only the 'session_id' key: a session id, a list of session ids, or {\"in\": [...]}. Recall (conclusions and messages) is restricted to the allowlist; unsupported keys are rejected. When session_id is also set, it must be included in the allowlist."
|
||||
},
|
||||
"target": {
|
||||
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
||||
"title": "Target",
|
||||
|
|
@ -2928,6 +2936,14 @@
|
|||
"title": "Reasoning Level",
|
||||
"description": "Level of reasoning to apply: minimal, low, medium, high, or max",
|
||||
"default": "low"
|
||||
},
|
||||
"response_format": {
|
||||
"anyOf": [
|
||||
{ "additionalProperties": true, "type": "object" },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"title": "Response Format",
|
||||
"description": "Optional JSON Schema (root type 'object') the response must conform to. When provided, `content` is a JSON string matching this schema. Only a conservative subset of JSON Schema is supported; unsupported schemas are rejected with 422. Constraint keywords (minItems, maxLength, ...) are hints to the model, not enforced server-side."
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
|
|
@ -2947,7 +2963,7 @@
|
|||
},
|
||||
"DreamType": {
|
||||
"type": "string",
|
||||
"enum": ["omni"],
|
||||
"enum": ["omni", "card_refresh"],
|
||||
"title": "DreamType",
|
||||
"description": "Types of dreams that can be triggered."
|
||||
},
|
||||
|
|
@ -3352,6 +3368,14 @@
|
|||
"title": "Session Id",
|
||||
"description": "Optional session ID within which to scope the representation"
|
||||
},
|
||||
"filters": {
|
||||
"anyOf": [
|
||||
{ "additionalProperties": true, "type": "object" },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"title": "Filters",
|
||||
"description": "Optional filters to scope the representation. This endpoint supports only the 'session_id' key: a session id, a list of session ids, or {\"in\": [...]}. When session_id is also set, it must be included in the allowlist."
|
||||
},
|
||||
"target": {
|
||||
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
||||
"title": "Target",
|
||||
|
|
@ -3506,6 +3530,12 @@
|
|||
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
||||
"title": "Session Id",
|
||||
"description": "Session ID to scope the dream to if specified"
|
||||
},
|
||||
"rebuild": {
|
||||
"type": "boolean",
|
||||
"title": "Rebuild",
|
||||
"description": "card_refresh dreams only: rebuild the peer card solely from observations currently in the collection, without injecting the existing card (use after removals)",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
|
|
|
|||
Loading…
Reference in New Issue