@springbrand/agent-runtime 0.1.0 → 0.1.1
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.
package/package.json
CHANGED
package/src/kernel/profile.ts
CHANGED
|
@@ -84,7 +84,6 @@ export interface RuntimeProfile {
|
|
|
84
84
|
denyPolicy?: RuntimeDenyPolicy;
|
|
85
85
|
enabledSubagents: readonly string[];
|
|
86
86
|
mcpServers: readonly RuntimeMcpServer[];
|
|
87
|
-
enabledExtensions: readonly string[];
|
|
88
87
|
executionLevel: ExecutionLevel;
|
|
89
88
|
memory: RuntimeMemoryProfile;
|
|
90
89
|
}
|
|
@@ -109,7 +108,6 @@ export function freezeRuntimeProfile(profile: RuntimeProfile): RuntimeProfile {
|
|
|
109
108
|
: undefined,
|
|
110
109
|
enabledSubagents: Object.freeze([...profile.enabledSubagents]),
|
|
111
110
|
mcpServers: Object.freeze(profile.mcpServers.map((server) => Object.freeze({ ...server }))),
|
|
112
|
-
enabledExtensions: Object.freeze([...profile.enabledExtensions]),
|
|
113
111
|
memory: Object.freeze({ ...profile.memory }),
|
|
114
112
|
};
|
|
115
113
|
return Object.freeze(frozen);
|
|
@@ -45,7 +45,7 @@ interface PiAssemblySnapshot {
|
|
|
45
45
|
>;
|
|
46
46
|
readonly profile: Pick<
|
|
47
47
|
RuntimeProfile,
|
|
48
|
-
"denyPolicy" | "
|
|
48
|
+
"denyPolicy" | "mcpServers"
|
|
49
49
|
>;
|
|
50
50
|
readonly bindings: {
|
|
51
51
|
readonly platform: Pick<RuntimePlatformPort, "loader">;
|
|
@@ -453,7 +453,7 @@ async function preparePiAssembly(
|
|
|
453
453
|
const extensions = await assemblePiExtensions({
|
|
454
454
|
extensions: snapshot.pi.extensions,
|
|
455
455
|
published: extensionNames,
|
|
456
|
-
enabled:
|
|
456
|
+
enabled: extensionNames,
|
|
457
457
|
authorized: extensionNames,
|
|
458
458
|
load: async (extension) => {
|
|
459
459
|
const workspacePermission =
|
|
@@ -2,7 +2,9 @@ import type { StreamFn } from "@earendil-works/pi-agent-core";
|
|
|
2
2
|
import {
|
|
3
3
|
createModels,
|
|
4
4
|
createProvider,
|
|
5
|
+
lazyStream,
|
|
5
6
|
type Api,
|
|
7
|
+
type AssistantMessageEvent,
|
|
6
8
|
type Model,
|
|
7
9
|
type MutableModels,
|
|
8
10
|
} from "@earendil-works/pi-ai";
|
|
@@ -44,19 +46,57 @@ const CATALOGS = {
|
|
|
44
46
|
} satisfies Record<RuntimeModelProtocol, readonly Model<Api>[]>;
|
|
45
47
|
|
|
46
48
|
const PROVIDER_MAX_RETRIES = 2;
|
|
49
|
+
const MODEL_STREAM_STALL_TIMEOUT_MS = 120_000;
|
|
50
|
+
|
|
51
|
+
async function* stopStalledModelStream(
|
|
52
|
+
source: AsyncIterable<AssistantMessageEvent>,
|
|
53
|
+
watchdog: AbortController,
|
|
54
|
+
): AsyncGenerator<AssistantMessageEvent> {
|
|
55
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
56
|
+
while (true) {
|
|
57
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
58
|
+
const next = await Promise.race([
|
|
59
|
+
iterator.next(),
|
|
60
|
+
new Promise<never>((_, reject) => {
|
|
61
|
+
timer = setTimeout(() => {
|
|
62
|
+
const error = new Error(
|
|
63
|
+
`Model stream stalled for ${MODEL_STREAM_STALL_TIMEOUT_MS} ms`,
|
|
64
|
+
);
|
|
65
|
+
watchdog.abort(error);
|
|
66
|
+
reject(error);
|
|
67
|
+
}, MODEL_STREAM_STALL_TIMEOUT_MS);
|
|
68
|
+
}),
|
|
69
|
+
]).finally(() => {
|
|
70
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
71
|
+
});
|
|
72
|
+
if (next.done) {
|
|
73
|
+
throw new Error("Model stream ended without a terminal event");
|
|
74
|
+
}
|
|
75
|
+
yield next.value;
|
|
76
|
+
if (next.value.type === "done" || next.value.type === "error") return;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
47
79
|
|
|
48
80
|
/**
|
|
49
|
-
* 给模型请求补上可中断的 provider
|
|
81
|
+
* 给模型请求补上可中断的 provider 瞬时错误重试和空闲终止边界。
|
|
50
82
|
*
|
|
51
83
|
* Runtime Turn 和 SubAgent 在把 `Models.streamSimple` 交给 Pi 前调用;显式传入的重试次数优先。
|
|
52
84
|
*
|
|
53
|
-
* Pi 0.83 默认 `maxRetries` 为 0
|
|
85
|
+
* Pi 0.83 默认 `maxRetries` 为 0,且流无事件时会无限等待。这里补 2 次默认重试,
|
|
86
|
+
* 并在连续 120 秒没有模型事件时中止 provider、返回明确失败终态。
|
|
54
87
|
*/
|
|
55
88
|
export function withProviderRetry(streamFn: StreamFn): StreamFn {
|
|
56
89
|
return (model, context, options) =>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
90
|
+
lazyStream(model, async () => {
|
|
91
|
+
const watchdog = new AbortController();
|
|
92
|
+
const source = await streamFn(model, context, {
|
|
93
|
+
...options,
|
|
94
|
+
signal: options?.signal
|
|
95
|
+
? AbortSignal.any([options.signal, watchdog.signal])
|
|
96
|
+
: watchdog.signal,
|
|
97
|
+
maxRetries: options?.maxRetries ?? PROVIDER_MAX_RETRIES,
|
|
98
|
+
});
|
|
99
|
+
return stopStalledModelStream(source, watchdog);
|
|
60
100
|
});
|
|
61
101
|
}
|
|
62
102
|
|
package/src/plugins.ts
CHANGED
|
@@ -837,7 +837,6 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
837
837
|
denyPolicy: this.denyPolicy,
|
|
838
838
|
enabledSubagents: [...this.enabledSubagents],
|
|
839
839
|
mcpServers: [...this.connectors.values()],
|
|
840
|
-
enabledExtensions: [...this.extensions.keys()],
|
|
841
840
|
executionLevel: this.profile.executionLevel,
|
|
842
841
|
memory: this.memoryProfile,
|
|
843
842
|
});
|