pi-smart-router 0.19.1 → 0.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type Context,
|
|
7
7
|
type Model,
|
|
8
8
|
type SimpleStreamOptions,
|
|
9
|
-
streamSimple as
|
|
9
|
+
streamSimple as compatDelegateStream,
|
|
10
10
|
} from '@earendil-works/pi-ai/compat';
|
|
11
11
|
|
|
12
12
|
import { parseAssistantMessageError } from '../../../src/infrastructure/delegation/provider-error.js';
|
|
@@ -21,9 +21,55 @@ import {
|
|
|
21
21
|
type FailoverNoticeInfo,
|
|
22
22
|
type FlushDelegatedEventsOptions,
|
|
23
23
|
} from './delegation-runtime.js';
|
|
24
|
-
import type { StreamDelegationDeps } from './types.js';
|
|
24
|
+
import type { DelegateStreamFn, StreamDelegationDeps } from './types.js';
|
|
25
25
|
import { throwIfAborted } from './utils.js';
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Minimal structural view of pi's composed provider (pi-coding-agent
|
|
29
|
+
* `ModelRegistry.getProvider()` → `composeModelProvider`). Typed structurally
|
|
30
|
+
* because `getProvider` only exists on newer pi-coding-agent versions (0.84+);
|
|
31
|
+
* the extension must keep loading against older ones.
|
|
32
|
+
*/
|
|
33
|
+
interface ComposedProviderLike {
|
|
34
|
+
streamSimple: DelegateStreamFn;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type RegistryWithProviders = StreamDelegationDeps['modelRegistry'] & {
|
|
38
|
+
getProvider?: (providerId: string) => ComposedProviderLike | undefined;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the stream entrypoint for a delegation target (SP-238, #160).
|
|
43
|
+
*
|
|
44
|
+
* Priority:
|
|
45
|
+
* 1. Explicit `deps.delegateStream` injection (tests / operator override).
|
|
46
|
+
* 2. The **composed provider** from `modelRegistry.getProvider(model.provider)` —
|
|
47
|
+
* the same path pi's own agent loop delegates through. Its `streamSimple`
|
|
48
|
+
* checks extension-registered providers (`extension.streamSimple` when
|
|
49
|
+
* `model.api === extension.api`) before falling back to pi-ai's built-in
|
|
50
|
+
* registry, so custom-API models (claude-bridge et al.) resolve correctly.
|
|
51
|
+
* 3. Bare `pi-ai/compat streamSimple` — dispatches only on `model.api` against
|
|
52
|
+
* pi-ai's private built-in registry; used when no composed provider exists
|
|
53
|
+
* (older pi-coding-agent, or providers never composed through ModelRuntime).
|
|
54
|
+
*/
|
|
55
|
+
function resolveDelegateStream(
|
|
56
|
+
targetModel: Model<Api>,
|
|
57
|
+
deps: StreamDelegationDeps,
|
|
58
|
+
): DelegateStreamFn {
|
|
59
|
+
if (deps.delegateStream) {
|
|
60
|
+
return deps.delegateStream;
|
|
61
|
+
}
|
|
62
|
+
const registry = deps.modelRegistry as RegistryWithProviders;
|
|
63
|
+
const provider =
|
|
64
|
+
typeof registry.getProvider === 'function'
|
|
65
|
+
? registry.getProvider(targetModel.provider)
|
|
66
|
+
: undefined;
|
|
67
|
+
if (provider && typeof provider.streamSimple === 'function') {
|
|
68
|
+
return (model, context, options) => provider.streamSimple(model, context, options);
|
|
69
|
+
}
|
|
70
|
+
return compatDelegateStream;
|
|
71
|
+
}
|
|
72
|
+
|
|
27
73
|
function isTerminalEvent(
|
|
28
74
|
event: AssistantMessageEvent,
|
|
29
75
|
): event is Extract<AssistantMessageEvent, { type: 'done' | 'error' }> {
|
|
@@ -52,7 +98,7 @@ export async function collectDelegatedStream(
|
|
|
52
98
|
options,
|
|
53
99
|
headroomContext,
|
|
54
100
|
);
|
|
55
|
-
const delegateStream = deps
|
|
101
|
+
const delegateStream = resolveDelegateStream(targetModel, deps);
|
|
56
102
|
const inner = delegateStream(targetModel, context, delegationOptions);
|
|
57
103
|
const events: AssistantMessageEvent[] = [];
|
|
58
104
|
let finalMessage: AssistantMessage | undefined;
|
|
@@ -119,7 +165,7 @@ export async function pipeDelegatedStream(
|
|
|
119
165
|
options,
|
|
120
166
|
headroomContext,
|
|
121
167
|
);
|
|
122
|
-
const delegateStream = deps
|
|
168
|
+
const delegateStream = resolveDelegateStream(targetModel, deps);
|
|
123
169
|
const inner = delegateStream(targetModel, context, delegationOptions);
|
|
124
170
|
const events: AssistantMessageEvent[] = [];
|
|
125
171
|
let finalMessage: AssistantMessage | undefined;
|
|
@@ -57,7 +57,12 @@ export interface StreamDelegationDeps {
|
|
|
57
57
|
/** Cheap scope fingerprint check before each routed turn. */
|
|
58
58
|
ensureFleetFresh?: () => Promise<void>;
|
|
59
59
|
readonly executionLedger: ExecutionLedger;
|
|
60
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Injectable stream override for tests; when unset, delegation resolves the
|
|
62
|
+
* stream through `modelRegistry.getProvider(...)` (composed provider, which
|
|
63
|
+
* knows extension-registered custom APIs — SP-238, #160), falling back to
|
|
64
|
+
* pi-ai/compat `streamSimple` when no composed provider exists.
|
|
65
|
+
*/
|
|
61
66
|
delegateStream?: DelegateStreamFn;
|
|
62
67
|
/** Injectable planning delegate sub-call; production uses frontier stream delegate. */
|
|
63
68
|
spawnPlanningDelegate?: PlanningDelegateSpawnFn;
|