docs: make technical prose concrete
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/llm/llm-pi-ai/README.md
|
||||
README.md: 7151fdf5b63f48e625d00a92dc42aa24b7de2f31
|
||||
README.zh.md: 0bfd5c706e01dd4448edb9cf0eec812831f68093
|
||||
README.md: f6a1eefe6083d801009a5b788a07b58d6e696a5a
|
||||
README.zh.md: f4c5ddd6dbe05ae709145cfac341f17a716bac82
|
||||
|
||||
@@ -173,7 +173,7 @@ Conversion preserves logical request order without adding text, while the select
|
||||
|
||||
#### What the model sees
|
||||
|
||||
pi-ai events become harness reasoning, text, tool-call, usage, and finish chunks. Parsed tool arguments cross the harness boundary as raw JSON strings.
|
||||
pi-ai events become harness reasoning, text, tool-call, usage, and finish chunks. The adapter passes parsed tool arguments to the harness as raw JSON strings.
|
||||
|
||||
#### Token effect
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ pi-ai 会安装多个提供方 SDK,并延迟加载 catalog 模型所选的 SDK
|
||||
|
||||
#### 模型看到的内容
|
||||
|
||||
pi-ai 事件会变为 harness 推理、文本、工具调用、usage 与 finish 分片。已解析工具参数以原始 JSON 字符串形式通过 harness 边界传递。
|
||||
pi-ai 事件会变为 harness 推理、文本、工具调用、usage 与 finish 分片。适配器把解析后的工具参数作为原始 JSON 字符串传给 harness。
|
||||
|
||||
#### Token 影响
|
||||
|
||||
|
||||
@@ -145,12 +145,12 @@ export type PiAiReasoningEfforts = Partial<Record<ModelThinkingLevel, string | n
|
||||
* default) or per model (winning over the route). Only the switches pi-ai's
|
||||
* reasoning dispatch reads are offered; the rest of pi-ai's compat surface
|
||||
* keeps its baseURL-derived auto-detection. pi-ai types both fields only on
|
||||
* `OpenAICompletionsCompat` — the other wire protocols carry their reasoning
|
||||
* shape in the protocol itself — so resolution rejects a model-level switch
|
||||
* `OpenAICompletionsCompat` — the other wire protocols define their reasoning
|
||||
* fields in the protocol itself — so resolution rejects a model-level switch
|
||||
* anywhere else, while a route-level default skips past models it cannot fit.
|
||||
*/
|
||||
export interface PiAiCompatProfile {
|
||||
/** Reasoning parameter shape the endpoint expects; absent keeps the catalog entry's, then pi-ai's baseURL-derived guess. */
|
||||
/** Reasoning parameter format the endpoint expects; absent keeps the catalog entry's, then pi-ai's baseURL-derived guess. */
|
||||
thinkingFormat?: PiAiThinkingFormat
|
||||
/** Whether the endpoint accepts `reasoning_effort`; absent keeps the catalog entry's, then pi-ai's baseURL-derived guess. */
|
||||
supportsReasoningEffort?: boolean
|
||||
|
||||
@@ -163,12 +163,12 @@ const compatProfile: z<PiAiCompatProfile> = z.object({
|
||||
/**
|
||||
* Keys are the offered levels, values their wire spellings. A valueless key
|
||||
* (`off:`) survives validation because schemastery passes nullable data
|
||||
* through before any member schema runs — `z.const(null)` only shapes the
|
||||
* error for non-null wrong values and what a configuration surface renders.
|
||||
* through before any member schema runs — `z.const(null)` only controls the
|
||||
* error for non-null wrong values and what a configuration UI renders.
|
||||
* Only resolution decides which levels may leave the value empty, so the
|
||||
* diagnostic can name the route and model. The assertion narrows
|
||||
* schemastery's `Dict`, which types every literal key as required; dict
|
||||
* validation is per-present-key, so the runtime shape is the partial record.
|
||||
* validation checks only present keys, so the runtime value is a partial record.
|
||||
*/
|
||||
const reasoningEfforts = z.dict(
|
||||
z.union([z.string(), z.const(null)]),
|
||||
@@ -237,7 +237,7 @@ export function assertServiceable(config: Config): void {
|
||||
resolveProfiles(config.providers)
|
||||
}
|
||||
|
||||
/** Reject a pre-release profile shape, naming the replacement. */
|
||||
/** Reject removed pre-release profile fields and name their replacements. */
|
||||
function rejectRemovedFields(provider: string, source: PiAiProviderProfile): void {
|
||||
const legacy = source as PiAiProviderProfile & {
|
||||
provider?: unknown
|
||||
|
||||
@@ -184,8 +184,8 @@ export interface PreparedLlmCall {
|
||||
/**
|
||||
* Provider-wire adapter for the harness message and stream vocabulary. Register implementations
|
||||
* with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include
|
||||
* `attributionHeaders()`; prove that at the wire or library header-hook boundary. The direct-fetch
|
||||
* DeepSeek and library-backed pi-ai adapters intentionally exercise this contract through different internals.
|
||||
* `attributionHeaders()`; prove the headers are added in the wire request or library header hook. The direct-fetch
|
||||
* DeepSeek and library-backed pi-ai adapters meet this contract through different internals.
|
||||
*/
|
||||
export abstract class LlmAdapter {
|
||||
/**
|
||||
|
||||
@@ -30,8 +30,8 @@ export interface ToolMessageSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* What SHAPE of information a producer-supplied context carries, declared by
|
||||
* the producer beside the source fields it supplied.
|
||||
* The kind of information in producer-supplied context, declared by the
|
||||
* producer beside its provenance.
|
||||
*
|
||||
* `MessageSource.kind` answers *who produced this*; `form` answers *what kind
|
||||
* of thing it is*, and the two axes are deliberately independent — several
|
||||
@@ -69,10 +69,10 @@ export interface ContextSnapshotSection {
|
||||
|
||||
/**
|
||||
* Producer-declared {@link ContextForm} and the fields that form requires,
|
||||
* mixed into the source shapes that carry one.
|
||||
* mixed into the source types that carry one.
|
||||
*
|
||||
* Discriminated by `form` so a producer cannot declare a shape without the
|
||||
* facts that shape is presented from: a `notice` must record its one-line
|
||||
* Discriminated by `form` so a producer cannot select a form without the
|
||||
* fields needed to present it: a `notice` must record its one-line
|
||||
* account, a `snapshot` its sections. Omitting `form` stays valid — an
|
||||
* undeclared context is the documented default.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Canonical provider-neutral message and streaming vocabulary for the loop,
|
||||
* session log, and plugins. Adapters alone translate provider wire shapes;
|
||||
* session log, and plugins. Adapters alone translate provider wire messages;
|
||||
* mapped interfaces make the content, source, and finish unions extensible.
|
||||
*/
|
||||
|
||||
@@ -21,13 +21,13 @@ export type {
|
||||
UserMessage,
|
||||
} from './message.ts'
|
||||
|
||||
/** Serializable provider-boundary facts; policy decides whether they are retryable. */
|
||||
/** Serializable provider or transport failure facts; policy decides whether they are retryable. */
|
||||
export interface LlmFailure {
|
||||
/** Human-readable provider or transport failure. */
|
||||
readonly message: string
|
||||
/** Stable provider-neutral machine-routing code. */
|
||||
readonly code: string
|
||||
/** HTTP status observed at the provider boundary, when available. */
|
||||
/** HTTP status returned by the provider, when available. */
|
||||
readonly status?: number
|
||||
/** Provider-requested delay in milliseconds, when valid and available. */
|
||||
readonly providerRetryAfterMs?: number
|
||||
@@ -89,7 +89,7 @@ export interface ContentBlockMap {
|
||||
'tool-result': ToolResultBlock
|
||||
}
|
||||
|
||||
/** The block `type` tag vocabulary; widens as plugins merge new shapes into {@link ContentBlockMap}. */
|
||||
/** The block `type` tag vocabulary; widens as plugins add entries to {@link ContentBlockMap}. */
|
||||
export type ContentBlockType = keyof ContentBlockMap
|
||||
/** Any known content block, derived from {@link ContentBlockMap}; switch on `type` and fall through unknowns (merge-extensible). */
|
||||
export type ContentBlock = ContentBlockMap[ContentBlockType]
|
||||
|
||||
@@ -206,7 +206,7 @@ export class TokenMeterService extends Service {
|
||||
if (state.stepStart === undefined
|
||||
|| state.stepStart.turn !== event.data.turn
|
||||
|| state.stepStart.step !== event.data.step) {
|
||||
throw new Error(`token meter: step/end at seq ${event.seq} has no matching step/start boundary`)
|
||||
throw new Error(`token meter: step/end at seq ${event.seq} has no matching step/start event`)
|
||||
}
|
||||
nextStepStart = undefined
|
||||
break
|
||||
@@ -223,7 +223,7 @@ export class TokenMeterService extends Service {
|
||||
if (stepStart === undefined
|
||||
|| stepStart.turn !== event.data.turn
|
||||
|| stepStart.step !== event.data.step) {
|
||||
throw new Error(`token meter: assistant/message at seq ${event.seq} has no matching step/start boundary`)
|
||||
throw new Error(`token meter: assistant/message at seq ${event.seq} has no matching step/start event`)
|
||||
}
|
||||
|
||||
// assistant/message is surface-mandatory at every append/seed boundary.
|
||||
|
||||
Reference in New Issue
Block a user