Skip to content

Commit ccedffd

Browse files
committed
feat(polyglot): add Echo and RESPAN integrations
1 parent 4d57f2c commit ccedffd

47 files changed

Lines changed: 2322 additions & 18 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.beads/interactions.jsonl‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,3 +799,8 @@
799799
{"id":"int-14c8e3bfe1278b9030ae6e2ee72c4d1a","kind":"field_change","created_at":"2026-09-21T08:08:08.181668Z","actor":"Dariusz Debowczyk","issue_id":"instructor-hw2f.5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Real MLX and PyTorch model paths, external packaging, PHP interoperability, and ownership boundaries verified."}}
800800
{"id":"int-3e7d2a5accfa1488a1d8bba8eff55a94","kind":"field_change","created_at":"2026-09-21T08:08:17.292784Z","actor":"Dariusz Debowczyk","issue_id":"instructor-hw2f","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Independent typed-decision model lab extracted; PHP HTTP integration and both real model runtimes verified."}}
801801
{"id":"int-2e533ec452bad80553bf632c37f6fa3f","kind":"field_change","created_at":"2026-09-21T09:49:14.651094Z","actor":"Dariusz Debowczyk","issue_id":"instructor-j8ny","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Pinned Jeff model adapter, truthful wire profile, real checkpoint, packaging, and Polyglot HTTP interoperability completed."}}
802+
{"id":"int-21826a04adb5519602fa9c6daada5d04","kind":"field_change","created_at":"2026-09-26T10:25:30.368479Z","actor":"Dariusz Debowczyk","issue_id":"instructor-asjd.1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Implemented and verified ternary Noul probability domain"}}
803+
{"id":"int-d2b254fdf07f54d2c645058e51e17eec","kind":"field_change","created_at":"2026-09-26T10:29:48.204499Z","actor":"Dariusz Debowczyk","issue_id":"instructor-asjd.2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Implemented and verified RESPAN driver contract"}}
804+
{"id":"int-271e102295da9d37c967911d24ba58d3","kind":"field_change","created_at":"2026-09-26T10:33:49.895323Z","actor":"Dariusz Debowczyk","issue_id":"instructor-asjd.3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"RESPAN is registered, documented, and capability-preflighted"}}
805+
{"id":"int-2258b9aaf8cc21760a1779f571d91bf3","kind":"field_change","created_at":"2026-09-26T10:38:00.139291Z","actor":"Dariusz Debowczyk","issue_id":"instructor-asjd.4","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Deterministic QA passed and live entitlement outcome recorded"}}
806+
{"id":"int-a54bbb6ecf25a91ba75c8107230e94a7","kind":"field_change","created_at":"2026-09-26T10:38:00.421889Z","actor":"Dariusz Debowczyk","issue_id":"instructor-asjd","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"RESPAN Decision support implemented, verified, documented, and live-tested to the account entitlement boundary"}}

‎.env-dist‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ ANYSCALE_API_KEY=''
1414
AZURE_OPENAI_API_KEY=''
1515
CEREBRAS_API_KEY=''
1616
COHERE_API_KEY=''
17+
ECHO_API_KEY=''
1718
FIREWORKS_API_KEY=''
1819
GEMINI_API_KEY=''
1920
GROQ_API_KEY=''

‎docs/mint.json‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"group": "Release Notes",
2626
"pages": [
2727
"release-notes/versions",
28+
"release-notes/v2.12.0",
2829
"release-notes/v2.11.0",
2930
"release-notes/v2.10.1",
3031
"release-notes/v2.10.0",
@@ -290,6 +291,7 @@
290291
"packages/polyglot/decision/classifier-dev",
291292
"packages/polyglot/decision/jeff",
292293
"packages/polyglot/decision/laya",
294+
"packages/polyglot/decision/respan",
293295
"packages/polyglot/decision/evaluation",
294296
"packages/polyglot/decision/errors-testing"
295297
]

‎docs/release-notes/v2.12.0.mdx‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
title: 'v2.12.0'
3+
---
4+
5+
v2.12.0 adds vector retrieval and structured decisions to InstructorPHP,
6+
expands exact-model metadata, and brings new Echo and RESPAN integrations. It
7+
also includes an embedding configuration cutover; review the upgrade notes
8+
before updating.
9+
10+
## Retrieval and agent knowledge access
11+
12+
- The new `cognesy/instructor-retrieval` package provides document processing,
13+
vector storage, semantic search, bounded context assembly, and citations.
14+
Bundled stores include in-memory, pgvector, Qdrant, Typesense, Meilisearch,
15+
Weaviate, and Milvus.
16+
- Retrieval composes with Polyglot Embeddings and leaves answer generation to
17+
the application, so callers control how evidence enters inference requests.
18+
- Agents can opt into bounded search and evidence-reading tools. Query, result,
19+
context, and read sizes are policy-controlled. Evidence reads pass through
20+
an application-owned authorization boundary.
21+
22+
## Structured decisions and model metadata
23+
24+
- Polyglot adds a typed Decision runtime for Noul, Choice, and Score questions.
25+
Adapters cover Classifier.dev, Jeff, Laya, TypeSafe, and RESPAN.
26+
- Noul answers can carry positive, negative, and unknown probabilities. RESPAN
27+
supports Noul questions and reports access failures separately from request
28+
validation errors.
29+
- Exact Embedding and Decision model catalogs expose reviewed capabilities and
30+
limits, with pricing where available. Examples show model metadata and cost
31+
estimates.
32+
33+
## Provider and integration updates
34+
35+
- The Echo inference driver supports Fulcrum's persona-based writing API and
36+
requires a non-empty `persona` option on each request or preset.
37+
- Embedding request model overrides now select the effective model for catalog
38+
lookup and provider request construction. Missing provider token counts
39+
remain unknown instead of being converted to zero.
40+
- The cURL transport negotiates HTTP/2 over TLS by default and handles interim
41+
response headers before the final response.
42+
43+
## Upgrade Notes
44+
45+
- Embedding configuration no longer accepts `dimensions`, `defaultDimensions`,
46+
or `maxInputs` in `EmbeddingsConfig`, DSNs, presets, or Laravel and Symfony
47+
embedding connection configuration. Set a requested dimension in request
48+
options, for example `withOptions(['dimensions' => 256])`. Inject an
49+
Embedding model catalog into `EmbeddingsRuntime` when catalog-based
50+
input-limit checks are required.
51+
- Embedding usage counts and totals can now be `null` when a provider omits
52+
them, and embedding cost calculation can return `null`. Handle unknown usage
53+
explicitly. Use `EmbeddingsUsage::zero()` for a known zero total; `none()`
54+
represents unknown usage.
55+
- Add `ECHO_API_KEY` or `RESPAN_API_KEY` only for applications that use the
56+
corresponding provider.

‎packages/instructor/docs/misc/llm_providers.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The following providers have built-in presets:
4141
| Cohere | `cohere` |
4242
| DeepSeek | `deepseek` |
4343
| DeepSeek (Reasoning) | `deepseek-r` |
44+
| Echo (Fulcrum) | `echo` |
4445
| Fireworks | `fireworks` |
4546
| Google Gemini | `gemini` |
4647
| Gemini (OpenAI-compatible) | `gemini-oai` |

‎packages/polyglot/docs/advanced/connection-mgmt.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ Polyglot ships with the following driver types:
7474
| `cerebras` | Cerebras |
7575
| `cohere` | Cohere |
7676
| `deepseek` | DeepSeek |
77+
| `echo` | Echo by Fulcrum (persona voice writing) |
7778
| `fireworks` | Fireworks AI |
7879
| `glm` | GLM |
7980
| `groq` | Groq |

‎packages/polyglot/docs/decision/_meta.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ order:
77
- classifier-dev
88
- jeff
99
- laya
10+
- respan
1011
- evaluation
1112
- errors-testing
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
title: RESPAN Span-01 Backend
3+
description: Score conversation behaviors with RESPAN while preserving not-observable probability.
4+
---
5+
6+
<!-- markdownlint-disable MD013 -->
7+
8+
The `respan` driver connects Polyglot Decision to RESPAN's hosted
9+
[`POST /api/v1/scores`](https://www.respan.ai/docs/apis/respan-models/score-span-behaviors)
10+
endpoint. Span-01 evaluates plain-language behavior definitions against one
11+
conversation span and returns present, absent, and not-observable probabilities.
12+
13+
## Configure the driver
14+
15+
Set the RESPAN API key:
16+
17+
```dotenv
18+
RESPAN_API_KEY=your-key
19+
```
20+
21+
Then select the bundled preset:
22+
23+
```php
24+
use Cognesy\Polyglot\Decision\Decision;
25+
26+
$decision = Decision::using('respan');
27+
```
28+
29+
The preset targets `https://api.respan.ai/api/v1/scores` with
30+
`span-01-free`. Override the model with `span-01-pro` when the organization has
31+
Span-01 access and sufficient credits.
32+
33+
## Conversation input
34+
35+
RESPAN requires an explicit conversation boundary. Pass a JSON object whose
36+
`input` list contains preceding messages and whose `output` object contains the
37+
single turn being judged:
38+
39+
```php
40+
use Cognesy\Polyglot\Decision\Collections\Questions;
41+
use Cognesy\Polyglot\Decision\Data\JsonContent;
42+
use Cognesy\Polyglot\Decision\Questions\Noul;
43+
44+
$answers = $decision
45+
->withInput(JsonContent::object([
46+
'input' => [
47+
['role' => 'user', 'content' => 'My order is late again.'],
48+
],
49+
'output' => [
50+
'role' => 'assistant',
51+
'content' => 'I am sorry. I will check the shipment now.',
52+
],
53+
]))
54+
->withQuestions(Questions::of(
55+
new Noul('apology', 'The assistant apologizes for a problem.'),
56+
))
57+
->get();
58+
59+
$answer = $answers->noul('apology');
60+
$present = $answer->probabilities()->positive();
61+
$absent = $answer->probabilities()->negative();
62+
$unknown = $answer->probabilities()->unknown();
63+
```
64+
65+
The adapter does not guess conversation turns from a string or unstructured
66+
list. Each message must have text `content`; `role` is optional but must be a
67+
non-empty string when present.
68+
69+
## Primitive and answer semantics
70+
71+
| Decision primitive | Span-01 representation | Capability |
72+
| --- | --- | --- |
73+
| Noul | One independent behavior definition | Native |
74+
| Choice | Not supported by this endpoint | Unsupported |
75+
| Score | Not supported by this endpoint | Unsupported |
76+
77+
Noul instructions become the behavior definition. Optional true and false
78+
criteria are rendered as explicit `Present when` and `Absent when` guidance.
79+
RESPAN evaluates all behaviors independently against the same span.
80+
81+
`NoulAnswer::probability()` remains the positive/present probability. The full
82+
`NoulProbabilities` value exposes positive, negative, and unknown values.
83+
`confidence()` is the greater of positive and negative; it never treats
84+
not-observable probability as evidence for absence.
85+
86+
## Usage, identity, and failures
87+
88+
- `usage.input_tokens` becomes `DecisionUsage::inputTokens()`.
89+
- Output tokens remain unknown because Span-01 does not generate output.
90+
- `X-Respan-Log-Id` becomes `DecisionResponse::providerRequestId()`.
91+
- HTTP 429 and transient dependency/service failures use the normal Decision
92+
retry policy and preserve `Retry-After`.
93+
- Missing credentials, unavailable organization entitlement, and insufficient
94+
pro credits are non-retryable and reported separately from invalid payloads.
95+
96+
The bundled model records advertise zero pricing for `span-01-free` and
97+
`$0.02` per million input tokens for `span-01-pro`. No token ceiling is recorded
98+
because RESPAN does not publish a numeric limit.
99+
100+
The initial driver deliberately does not send `respan_params`. Polyglot does not
101+
implicitly export telemetry identities or metadata as provider logging data.

‎packages/polyglot/docs/essentials/request-options.md‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,40 @@ $response = Inference::using('anthropic')
9797
->get();
9898
```
9999

100+
### Echo (persona)
101+
102+
[Echo](https://echo.fulcrum.inc/dev/) writes in a named writer's voice. Every
103+
request needs a `persona` - the writer's name - sent as a top-level body field.
104+
Polyglot rejects a request without a non-empty `persona` before sending it.
105+
106+
```php
107+
$response = Inference::using('echo')
108+
->withMessages(Messages::fromString('Explain GRPO in one paragraph.'))
109+
->withOptions(['persona' => 'Joan Didion'])
110+
->get();
111+
```
112+
113+
To pin a default voice, set `options.persona` in an app-owned preset; a
114+
request-level `persona` overrides it:
115+
116+
```yaml
117+
driver: echo
118+
apiUrl: 'https://echo.fulcrum.inc/api/v1'
119+
apiKey: '${ECHO_API_KEY}'
120+
endpoint: /chat/completions
121+
model: echo
122+
maxTokens: 20480
123+
options:
124+
persona: 'Joan Didion'
125+
```
126+
127+
For a writer Echo does not know, paste a few of their writing samples into the
128+
message and pass their name as `persona`. Echo is stateless, so send the whole
129+
conversation on every turn. Reasoning is always on (`low` by default); request
130+
more with `withReasoning(ReasoningSelection::effort(ReasoningEffort::High))`.
131+
Higher efforts can take a minute or more, so prefer streaming and a generous
132+
HTTP timeout.
133+
100134
## Retry Policy
101135

102136
Retry behavior is configured explicitly through `withRetryPolicy()` -- never place it

‎packages/polyglot/docs/internals/providers.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ Supported inference drivers:
140140
| `cerebras` | spec: `CerebrasBodyFormat` | Cerebras |
141141
| `cohere` | spec: `CohereV2BodyFormat` + `CohereV2RequestAdapter` | Cohere v2 |
142142
| `deepseek` | spec: `DeepseekBodyFormat` | DeepSeek V4; tools and JSON Output, with JSON Schema degraded to JSON object |
143+
| `echo` | spec: `EchoBodyFormat` + `OpenAICompatibleReasoningAdapter` | Echo by Fulcrum; requires `persona` option, keeps `max_tokens` |
143144
| `fireworks` | spec: `FireworksBodyFormat` | Fireworks AI |
144145
| `gemini` | spec: `GeminiBodyFormat` + `GeminiRequestAdapter` | Google Gemini native API |
145146
| `gemini-oai` | spec: `GeminiOAIBodyFormat` + `GeminiOAIRequestAdapter` | Gemini via OpenAI-compatible endpoint |

0 commit comments

Comments
 (0)