@code-yeongyu/senpi 2026.10.26-1 → 2026.10.26-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.
- package/CHANGELOG.md +24 -0
- package/dist/bundle/chunks/{anthropic-messages-M235FJQV.js → anthropic-messages-ODSFJCXR.js} +1 -1
- package/dist/bundle/chunks/{args-FBNJOJSR.js → args-SWKJAYQD.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-YQRTQ7H6.js → azure-openai-responses-REGXS4XO.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/dist/bundle/chunks/chunk-2XF6W6F6.js +410 -0
- package/dist/bundle/chunks/{chunk-DMFAVE5N.js → chunk-4QVORFQ2.js} +1 -1
- package/dist/bundle/chunks/{chunk-ZXHLH4MW.js → chunk-5W3DTM2J.js} +1 -1
- package/dist/bundle/chunks/{chunk-QREKAXKX.js → chunk-6GAMRAVM.js} +5 -5
- package/dist/bundle/chunks/{chunk-MSHRIZGT.js → chunk-7IZH2KQX.js} +3 -3
- package/dist/bundle/chunks/{chunk-PH3JDRB2.js → chunk-ARSENVDY.js} +1 -1
- package/dist/bundle/chunks/{chunk-5KZH6EYQ.js → chunk-CNDPCYNT.js} +1 -1
- package/dist/bundle/chunks/{chunk-DYWIFF2Q.js → chunk-CYOHFREV.js} +1 -1
- package/dist/bundle/chunks/{chunk-3LPWILUZ.js → chunk-DNDZPKIQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-ZLIVZQDY.js → chunk-EQNUL2WB.js} +1 -1
- package/dist/bundle/chunks/{chunk-5FQMNHXV.js → chunk-ESNSRUW4.js} +1 -1
- package/dist/bundle/chunks/{chunk-LO5MYLGF.js → chunk-FQDARFHT.js} +1 -1
- package/dist/bundle/chunks/{chunk-7KOUQSBX.js → chunk-GPPOPK76.js} +3 -3
- package/dist/bundle/chunks/chunk-I2WFLKZ2.js +5 -0
- package/dist/bundle/chunks/{chunk-I7QWTWVZ.js → chunk-IHKHCWWG.js} +1 -1
- package/dist/bundle/chunks/{chunk-MY4ZD3EW.js → chunk-IY4G44MN.js} +1 -1
- package/dist/bundle/chunks/{chunk-OQ3WDMB3.js → chunk-JH7MVRNJ.js} +1 -1
- package/dist/bundle/chunks/chunk-KBSFTXAT.js +2 -0
- package/dist/bundle/chunks/{chunk-UW6M3EXY.js → chunk-KRO63T4Q.js} +1 -1
- package/dist/bundle/chunks/{chunk-J5FCH7TI.js → chunk-KTDIIF2F.js} +1 -1
- package/dist/bundle/chunks/{chunk-3WP5RFQR.js → chunk-NDNIMC5W.js} +1 -1
- package/dist/bundle/chunks/{chunk-CDQPA4FP.js → chunk-ODRGPC5S.js} +1 -1
- package/dist/bundle/chunks/{chunk-3A3XCLNH.js → chunk-PDG4XWO2.js} +1 -1
- package/dist/bundle/chunks/{chunk-QYFOHFPS.js → chunk-PPECSSWX.js} +1 -1
- package/dist/bundle/chunks/{chunk-5LWUUXMH.js → chunk-PY4ZQHTN.js} +1 -1
- package/dist/bundle/chunks/{chunk-EZP6AYW2.js → chunk-RPW3XQW3.js} +22 -22
- package/dist/bundle/chunks/{chunk-SOXQ42VS.js → chunk-RQ5JTXUC.js} +1 -1
- package/dist/bundle/chunks/{chunk-JFQUWEN7.js → chunk-TQ67PB7U.js} +2 -2
- package/dist/bundle/chunks/{chunk-6U3TBFBA.js → chunk-UJPG4ROT.js} +1 -1
- package/dist/bundle/chunks/{chunk-UDM7VO6O.js → chunk-XM36IFP3.js} +1 -1
- package/dist/bundle/chunks/{chunk-XQ45JMGN.js → chunk-Z6BREXV3.js} +1 -1
- package/dist/bundle/chunks/{chunk-ADQAPDPV.js → chunk-ZP6JJDYV.js} +1 -1
- package/dist/bundle/chunks/{cli-main-55EQA5PS.js → cli-main-Q2GA53XM.js} +1 -1
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-ZJQGIIRC.js → cloudflare-workers-ai-system-one-WDHT7BBV.js} +1 -1
- package/dist/bundle/chunks/cursor-agent.js +1 -1
- package/dist/bundle/chunks/devin-agent.js +1 -1
- package/dist/bundle/chunks/{dispatch-C2IBP5VV.js → dispatch-5R3TYAYB.js} +3 -3
- package/dist/bundle/chunks/{google-generative-ai-5G4RIQA6.js → google-generative-ai-FHYFXKLA.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-ALD4P27O.js → google-vertex-5DWE5U5K.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-PEIKGCKZ.js → help-fast-path-FETLIF3W.js} +1 -1
- package/dist/bundle/chunks/{host-command-657VCQ34.js → host-command-XEB7SHT3.js} +1 -1
- package/dist/bundle/chunks/{host-session-command-OV5XDOJK.js → host-session-command-FFN52LXJ.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-MLXSYK2H.js → interactive-mode-5DEKY3YW.js} +1 -1
- package/dist/bundle/chunks/{mistral-conversations-RAE4K2XY.js → mistral-conversations-I2PI7DDF.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-774MACJU.js → multi-session-host-OPR5VBFO.js} +3 -3
- package/dist/bundle/chunks/{openai-codex-responses-3CW4R7TG.js → openai-codex-responses-WSEX6SH7.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-5UIJXQUF.js → openai-completions-YCBHTBSS.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-2BO44MRW.js → openai-responses-GXNSQF4A.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-MZHVCX2S.js → package-manager-cli-W55E3LHP.js} +1 -1
- package/dist/bundle/chunks/{pi-messages-RF6GER4R.js → pi-messages-O6GISIRW.js} +1 -1
- package/dist/bundle/chunks/{role-ETSFSDTS.js → role-SHIZQKK4.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-ZMQB4GPO.js → rotation-stream-2PCZWNKF.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-UJXOIZCW.js → rpc-mode-IDUJTSYS.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-KA7LFFNK.js → schedule-command-B7RRSANU.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-MFWXUR7Z.js → session-control-endpoint-LMZH5JLH.js} +1 -1
- package/dist/bundle/chunks/{session-picker-BP33NRSL.js → session-picker-DTGBOXDR.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +41 -41
- package/dist/bundle/chunks/{typesafe-system-one-GNNZ5O5U.js → typesafe-system-one-XGYJJVSE.js} +1 -1
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/core/agent-session.d.ts +11 -1
- package/dist/core/agent-session.js +19 -2
- package/dist/core/extensions/builtin/compaction/index.js +7 -1
- package/dist/core/extensions/builtin/herdr/index.js +9 -5
- package/dist/core/extensions/builtin/mcp/auth/oauth-issuer.d.ts +6 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-issuer.js +25 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-provider.d.ts +3 -3
- package/dist/core/extensions/builtin/mcp/auth/oauth-provider.js +50 -19
- package/dist/core/extensions/builtin/mcp/auth/oauth-refresh.js +4 -3
- package/dist/core/extensions/builtin/mcp/auth/oauth.js +19 -12
- package/dist/core/extensions/builtin/mcp/modern/dispatch.js +1 -0
- package/dist/core/extensions/builtin/mcp/modern/parameter-headers.d.ts +4 -1
- package/dist/core/extensions/builtin/mcp/modern/parameter-headers.js +33 -35
- package/dist/core/extensions/builtin/mcp/modern/request.js +3 -0
- package/dist/core/extensions/builtin/mcp/modern/transport.d.ts +2 -0
- package/dist/core/extensions/builtin/mcp/modern/transport.js +4 -2
- package/dist/core/extensions/builtin/terminal/extension-state.js +2 -1
- package/dist/core/extensions/builtin/vertex-model-garden/auth.d.ts +9 -0
- package/dist/core/extensions/builtin/vertex-model-garden/auth.js +17 -1
- package/dist/core/extensions/builtin/websearch/websearch/providers/google.d.ts +6 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers/google.js +6 -1
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/lifecycle-children.d.ts +3 -1
- package/dist/core/lifecycle-children.js +79 -15
- package/dist/core/lifecycle-record.js +1 -24
- package/dist/core/lifecycle-session-binding.js +2 -1
- package/dist/core/lifecycle-wait-items.d.ts +17 -0
- package/dist/core/lifecycle-wait-items.js +72 -0
- package/dist/core/model-runtime.js +6 -1
- package/dist/core/provider-api-key-auth.d.ts +6 -1
- package/dist/core/provider-api-key-auth.js +11 -4
- package/dist/core/provider-composer.d.ts +8 -1
- package/dist/core/provider-composer.js +7 -3
- package/dist/core/sdk.js +4 -1
- package/dist/core/session-activity.js +2 -0
- package/dist/core/session-lifecycle-types.d.ts +20 -4
- package/dist/core/session-lifecycle.js +35 -4
- package/dist/core/structured-session-lane.d.ts +33 -0
- package/dist/core/structured-session-lane.js +62 -0
- package/dist/core/work-custody-record.d.ts +2 -1
- package/dist/core/work-custody-record.js +2 -0
- package/dist/core/work-obligations.d.ts +1 -1
- package/dist/core/work-obligations.js +8 -2
- package/dist/modes/json-event.d.ts +79 -1
- package/dist/modes/json-event.js +79 -1
- package/dist/modes/rpc/compact-content-index.d.ts +85 -0
- package/dist/modes/rpc/compact-content-index.js +254 -0
- package/dist/modes/rpc/compact-content-store.d.ts +6 -43
- package/dist/modes/rpc/compact-content-store.js +22 -157
- package/dist/modes/rpc/compact-index-pages.d.ts +12 -0
- package/dist/modes/rpc/compact-index-pages.js +31 -0
- package/dist/modes/rpc/compact-session-state.d.ts +11 -39
- package/dist/modes/rpc/compact-session-state.js +17 -26
- package/dist/modes/rpc/compact-spool-dir.d.ts +4 -1
- package/dist/modes/rpc/compact-spool-dir.js +41 -8
- package/dist/modes/rpc/compact-spool-storage.d.ts +53 -0
- package/dist/modes/rpc/compact-spool-storage.js +162 -0
- package/dist/modes/rpc/compact-storage-io.d.ts +2 -1
- package/dist/modes/rpc/compact-storage-io.js +7 -1
- package/dist/modes/rpc/compact-transition.d.ts +41 -0
- package/dist/modes/rpc/compact-transition.js +12 -0
- package/dist/modes/rpc/connection-handler.d.ts +2 -0
- package/dist/modes/rpc/connection-handler.js +12 -6
- package/dist/modes/rpc/host-ensure-start.js +5 -3
- package/dist/modes/rpc/security-presentations.js +2 -1
- package/dist/modes/rpc/session-binding.js +10 -0
- package/dist/modes/rpc/session-event-writer.d.ts +2 -0
- package/dist/modes/rpc/session-event-writer.js +2 -0
- package/dist/modes/rpc/session-record-stream.d.ts +3 -3
- package/dist/modes/rpc/session-record-stream.js +3 -3
- package/dist/modes/rpc/session-structured-lanes.d.ts +12 -0
- package/dist/modes/rpc/session-structured-lanes.js +24 -0
- package/dist/modes/rpc/session-worker-client.js +6 -5
- package/dist/modes/rpc/structured-session-records.d.ts +12 -0
- package/dist/modes/rpc/structured-session-records.js +88 -0
- package/docs/extensions.md +7 -1
- package/docs/rpc.md +17 -2
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-GQJYNFMO.js +0 -2
- package/dist/bundle/chunks/chunk-VICDRG3J.js +0 -410
- package/dist/bundle/chunks/chunk-VL7O5PO4.js +0 -5
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** Optional producer detail never determines custody. Lists are snapshots, bounded independently of activeCount. */
|
|
2
|
+
export function normalizeWaitItems(value, omitted) {
|
|
3
|
+
const byId = new Map();
|
|
4
|
+
if (Array.isArray(value)) {
|
|
5
|
+
for (const entry of value) {
|
|
6
|
+
if (typeof entry !== "object" || entry === null || !("id" in entry))
|
|
7
|
+
continue;
|
|
8
|
+
if (typeof entry.id !== "string" || entry.id.trim().length === 0)
|
|
9
|
+
continue;
|
|
10
|
+
const item = {
|
|
11
|
+
id: entry.id,
|
|
12
|
+
...("description" in entry && typeof entry.description === "string"
|
|
13
|
+
? { description: entry.description }
|
|
14
|
+
: {}),
|
|
15
|
+
...("startedAtMs" in entry &&
|
|
16
|
+
typeof entry.startedAtMs === "number" &&
|
|
17
|
+
Number.isFinite(entry.startedAtMs) &&
|
|
18
|
+
Math.abs(entry.startedAtMs) <= 8.64e15
|
|
19
|
+
? { startedAtMs: entry.startedAtMs }
|
|
20
|
+
: {}),
|
|
21
|
+
};
|
|
22
|
+
const previous = byId.get(item.id);
|
|
23
|
+
if (!previous || JSON.stringify(item) < JSON.stringify(previous))
|
|
24
|
+
byId.set(item.id, item);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const items = [...byId.values()].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
28
|
+
const omittedItems = Math.max(0, items.length - 32) +
|
|
29
|
+
(typeof omitted === "number" && Number.isSafeInteger(omitted) && omitted > 0 ? omitted : 0);
|
|
30
|
+
return {
|
|
31
|
+
...(items.length ? { items: items.slice(0, 32) } : {}),
|
|
32
|
+
...(omittedItems ? { omittedItems } : {}),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** The one rule for a wake_source_state producer's item list: `items` when set, else the legacy `monitors`. */
|
|
36
|
+
export function wakeSourceItems(data) {
|
|
37
|
+
return ("items" in data ? data.items : undefined) ?? ("monitors" in data ? data.monitors : undefined);
|
|
38
|
+
}
|
|
39
|
+
export function waitItemSignature(detail) {
|
|
40
|
+
return JSON.stringify([detail.items?.map((item) => [item.id, item.description]), detail.omittedItems]);
|
|
41
|
+
}
|
|
42
|
+
export function projectWaitItems(detail) {
|
|
43
|
+
return {
|
|
44
|
+
...(detail.items
|
|
45
|
+
? {
|
|
46
|
+
items: detail.items.map((item) => ({
|
|
47
|
+
id: item.id,
|
|
48
|
+
...(item.description === undefined ? {} : { label: item.description }),
|
|
49
|
+
...(item.startedAtMs === undefined ? {} : { startedAt: new Date(item.startedAtMs).toISOString() }),
|
|
50
|
+
})),
|
|
51
|
+
}
|
|
52
|
+
: {}),
|
|
53
|
+
...(detail.omittedItems ? { omittedItems: detail.omittedItems } : {}),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function readWaitItems(value, omitted) {
|
|
57
|
+
const items = Array.isArray(value)
|
|
58
|
+
? value.map((item) => {
|
|
59
|
+
if (typeof item !== "object" || item === null)
|
|
60
|
+
return item;
|
|
61
|
+
return {
|
|
62
|
+
...("id" in item ? { id: item.id } : {}),
|
|
63
|
+
...("label" in item ? { description: item.label } : {}),
|
|
64
|
+
...("startedAt" in item && typeof item.startedAt === "string"
|
|
65
|
+
? { startedAtMs: Date.parse(item.startedAt) }
|
|
66
|
+
: {}),
|
|
67
|
+
};
|
|
68
|
+
})
|
|
69
|
+
: undefined;
|
|
70
|
+
return projectWaitItems(normalizeWaitItems(items, omitted));
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=lifecycle-wait-items.js.map
|
|
@@ -245,7 +245,12 @@ export class ModelRuntime {
|
|
|
245
245
|
return base;
|
|
246
246
|
}
|
|
247
247
|
try {
|
|
248
|
-
|
|
248
|
+
// The reader runs only inside ambient auth resolution; composition itself stays credential-free.
|
|
249
|
+
const storedProviderEnv = async (sourceId) => {
|
|
250
|
+
const credential = await this.credentials.read(sourceId);
|
|
251
|
+
return credential?.type === "api_key" && credential.env ? { ...credential.env } : undefined;
|
|
252
|
+
};
|
|
253
|
+
const provider = composeModelProvider(providerId, base, this.config, extension, { storedProviderEnv });
|
|
249
254
|
this.compositionErrors.delete(providerId);
|
|
250
255
|
return provider;
|
|
251
256
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { type ApiKeyAuth, type AuthContext, type AuthResult, type ModelAuth, type Provider, type ProviderHeaders } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { ConfigValue } from "@earendil-works/pi-ai/utils/config-reference";
|
|
3
3
|
import type { ModelsJsonProvider } from "./model-config.ts";
|
|
4
|
+
/** Reads another provider's stored credential env: routing metadata only, never keys. */
|
|
5
|
+
export type StoredProviderEnvReader = (providerId: string) => Promise<Record<string, string> | undefined>;
|
|
4
6
|
interface AmbientAuthExtensionInput {
|
|
5
7
|
name?: string;
|
|
6
8
|
resolve(input: {
|
|
7
9
|
ctx: AuthContext;
|
|
8
10
|
signal: AbortSignal;
|
|
11
|
+
storedProviderEnv?: StoredProviderEnvReader;
|
|
9
12
|
}): Promise<AuthResult | undefined>;
|
|
10
13
|
}
|
|
11
14
|
interface ProviderAuthExtensionInput {
|
|
@@ -19,7 +22,9 @@ interface ProviderAuthExtensionInput {
|
|
|
19
22
|
oauth?: unknown;
|
|
20
23
|
ambientAuth?: AmbientAuthExtensionInput;
|
|
21
24
|
}
|
|
22
|
-
export declare function composeApiKeyAuth(providerId: string, base: Provider | undefined, config: ModelsJsonProvider | undefined, extension: ProviderAuthExtensionInput | undefined
|
|
25
|
+
export declare function composeApiKeyAuth(providerId: string, base: Provider | undefined, config: ModelsJsonProvider | undefined, extension: ProviderAuthExtensionInput | undefined, options?: {
|
|
26
|
+
storedProviderEnv?: StoredProviderEnvReader;
|
|
27
|
+
}): ApiKeyAuth | undefined;
|
|
23
28
|
export declare function configuredApiKey(config: ModelsJsonProvider | undefined, extension: ProviderAuthExtensionInput | undefined): ConfigValue | undefined;
|
|
24
29
|
export declare function configuredHeaders(config: ModelsJsonProvider | undefined, extension: ProviderAuthExtensionInput | undefined): Record<string, ConfigValue> | undefined;
|
|
25
30
|
export declare function withConfiguredAuth(auth: ModelAuth, headers: ProviderHeaders | undefined, authHeader: boolean): ModelAuth;
|
|
@@ -2,7 +2,7 @@ import { hasCredentialHeaders, } from "@earendil-works/pi-ai";
|
|
|
2
2
|
import { assertConfigReferenceAuthority } from "./config-reference-resolver.js";
|
|
3
3
|
import { checkConfiguredHeaderAuth, headerAuthResolutionSource } from "./provider-header-auth.js";
|
|
4
4
|
import { getConfigValueEnvVarNames, isCommandConfigValue, resolveConfigValueOrThrow, resolveHeadersOrThrow, } from "./resolve-config-value.js";
|
|
5
|
-
export function composeApiKeyAuth(providerId, base, config, extension) {
|
|
5
|
+
export function composeApiKeyAuth(providerId, base, config, extension, options) {
|
|
6
6
|
const inherited = base?.auth.apiKey;
|
|
7
7
|
const rawKey = configuredApiKey(config, extension);
|
|
8
8
|
const oauth = extension?.oauth ?? base?.auth.oauth;
|
|
@@ -15,7 +15,7 @@ export function composeApiKeyAuth(providerId, base, config, extension) {
|
|
|
15
15
|
// explicitly configured key, credential headers, or a base provider still
|
|
16
16
|
// win, and a resolution marked ambient never outranks a configured
|
|
17
17
|
// provider in automatic default selection (senpi#2327).
|
|
18
|
-
return ambientApiKeyAuth(providerId, ambient, rawHeaders, headerSource, authHeader);
|
|
18
|
+
return ambientApiKeyAuth(providerId, ambient, rawHeaders, headerSource, authHeader, options?.storedProviderEnv);
|
|
19
19
|
}
|
|
20
20
|
if (!inherited && rawKey === undefined && !headerSource && oauth) {
|
|
21
21
|
// An OAuth provider with no key, no credential headers and no base normally
|
|
@@ -119,16 +119,23 @@ function ambientOnlyAuth(providerId, oauth, rawHeaders, headerSource, authHeader
|
|
|
119
119
|
* is the only source — and `Models.checkAuth` resolves this auth, so the
|
|
120
120
|
* `ambient` marker reaches the provider's auth status.
|
|
121
121
|
*/
|
|
122
|
-
function ambientApiKeyAuth(providerId, ambient, rawHeaders, headerSource, authHeader) {
|
|
122
|
+
function ambientApiKeyAuth(providerId, ambient, rawHeaders, headerSource, authHeader, storedProviderEnv) {
|
|
123
123
|
const resolve = async (input) => {
|
|
124
|
-
const result = await ambient.resolve({
|
|
124
|
+
const result = await ambient.resolve({
|
|
125
|
+
ctx: input.ctx,
|
|
126
|
+
signal: input.signal,
|
|
127
|
+
...(storedProviderEnv ? { storedProviderEnv } : {}),
|
|
128
|
+
});
|
|
125
129
|
if (!result)
|
|
126
130
|
return undefined;
|
|
127
131
|
const explicitEnv = { ...(input.credential?.env ?? {}), ...(result.env ?? {}) };
|
|
128
132
|
const headerEnv = await configContextEnv(Object.values(rawHeaders ?? {}), input.ctx, explicitEnv);
|
|
129
133
|
const headers = await resolveHeadersOrThrow(rawHeaders, `provider "${providerId}"`, headerEnv);
|
|
134
|
+
// Stored-then-env (helpers.ts invariant): the provider's own stored env wins over ambient-resolved env.
|
|
135
|
+
const env = result.env || input.credential?.env ? { ...(result.env ?? {}), ...(input.credential?.env ?? {}) } : undefined;
|
|
130
136
|
return {
|
|
131
137
|
...result,
|
|
138
|
+
...(env ? { env } : {}),
|
|
132
139
|
auth: withConfiguredAuth(result.auth, headers, authHeader),
|
|
133
140
|
source: result.source ?? headerSource,
|
|
134
141
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type AnyModel, type Api, type AssistantMessageEventStream, type AuthCheck, type AuthContext, type AuthResult, type ClassifierApi, type ImageApi, type Model, type OAuthCredential, type OAuthCredentials, type OAuthLoginCallbacks, type Provider, type ProviderClassifier, type ProviderImages, type RefreshModelsContext, type SimpleStreamOptions, type TranscriptContext } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { RetryPolicyProfile } from "@earendil-works/pi-ai/utils/retry-profile/types";
|
|
3
3
|
import type { ModelConfig, ModelsJsonProvider } from "./model-config.ts";
|
|
4
|
+
import { type StoredProviderEnvReader } from "./provider-api-key-auth.ts";
|
|
4
5
|
import type { HeaderAuthStatusSource } from "./provider-header-auth.ts";
|
|
5
6
|
import { clearConfigValueCache } from "./resolve-config-value.ts";
|
|
6
7
|
export interface ExtensionOAuthConfig {
|
|
@@ -120,6 +121,8 @@ export interface ProviderAmbientAuth {
|
|
|
120
121
|
resolve(input: {
|
|
121
122
|
ctx: AuthContext;
|
|
122
123
|
signal: AbortSignal;
|
|
124
|
+
/** Read-only env of another provider's stored credential; routing metadata only, never keys. */
|
|
125
|
+
storedProviderEnv?(providerId: string): Promise<Record<string, string> | undefined>;
|
|
123
126
|
}): Promise<AuthResult | undefined>;
|
|
124
127
|
}
|
|
125
128
|
export type AuthStatus = {
|
|
@@ -133,7 +136,11 @@ export { configuredRequestAuthStatus, resolveCompatibilityRequestHeaders, resolv
|
|
|
133
136
|
export declare const clearApiKeyCache: typeof clearConfigValueCache;
|
|
134
137
|
export declare function validateExtensionProvider(providerId: string, base: Provider | undefined, modelsConfig: ModelsJsonProvider | undefined, extension: ProviderConfigInput): void;
|
|
135
138
|
/** Compose built-in, models.json, and extension layers without reading credentials. */
|
|
136
|
-
export declare function composeModelProvider(providerId: string, base: Provider | undefined, modelConfig: ModelConfig, extension: ProviderConfigInput | undefined
|
|
139
|
+
export declare function composeModelProvider(providerId: string, base: Provider | undefined, modelConfig: ModelConfig, extension: ProviderConfigInput | undefined,
|
|
140
|
+
/** Deferred ambient reads; the reader runs during auth resolution, never at composition. */
|
|
141
|
+
options?: {
|
|
142
|
+
storedProviderEnv?: StoredProviderEnvReader;
|
|
143
|
+
}): Provider;
|
|
137
144
|
/**
|
|
138
145
|
* Request shape a compatibility provider needs beside its credential. Headers are NOT
|
|
139
146
|
* part of it: a configured header value can be a `!command`, and resolving one requires
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getApiProvider, getCurrentTools, getProtocol, getToolCallFormat, isModelType, lazyStream, transformContext, wrapStreamWithToolCallMiddleware, } from "@earendil-works/pi-ai";
|
|
2
2
|
import { classifierErrorResult, imageErrorResult } from "@earendil-works/pi-ai/utils/model-operations";
|
|
3
|
-
import { composeApiKeyAuth, configuredHeaders, withConfiguredAuth } from "./provider-api-key-auth.js";
|
|
3
|
+
import { composeApiKeyAuth, configuredHeaders, withConfiguredAuth, } from "./provider-api-key-auth.js";
|
|
4
4
|
import { clearConfigValueCache, resolveHeadersOrThrow } from "./resolve-config-value.js";
|
|
5
5
|
export { configuredRequestAuthStatus, resolveCompatibilityRequestHeaders, resolveConfiguredModelHeaders, } from "./provider-request-auth.js";
|
|
6
6
|
export const clearApiKeyCache = clearConfigValueCache;
|
|
@@ -286,7 +286,9 @@ export function validateExtensionProvider(providerId, base, modelsConfig, extens
|
|
|
286
286
|
applyExtension(providerId, applyModelsJson(providerId, getAllProviderModels(base), modelsConfig, extension), extension, new Set((modelsConfig?.models ?? []).map((definition) => definition.id)));
|
|
287
287
|
}
|
|
288
288
|
/** Compose built-in, models.json, and extension layers without reading credentials. */
|
|
289
|
-
export function composeModelProvider(providerId, base, modelConfig, extension
|
|
289
|
+
export function composeModelProvider(providerId, base, modelConfig, extension,
|
|
290
|
+
/** Deferred ambient reads; the reader runs during auth resolution, never at composition. */
|
|
291
|
+
options) {
|
|
290
292
|
const config = modelConfig.getProvider(providerId);
|
|
291
293
|
let extensionOAuthCredential;
|
|
292
294
|
let refreshedExtensionModels;
|
|
@@ -309,7 +311,9 @@ export function composeModelProvider(providerId, base, modelConfig, extension) {
|
|
|
309
311
|
};
|
|
310
312
|
// Validate eagerly so registration/reload reports structural errors immediately.
|
|
311
313
|
getAllModels();
|
|
312
|
-
const apiKey = composeApiKeyAuth(providerId, base, config, extension
|
|
314
|
+
const apiKey = composeApiKeyAuth(providerId, base, config, extension, {
|
|
315
|
+
storedProviderEnv: options?.storedProviderEnv,
|
|
316
|
+
});
|
|
313
317
|
const oauth = composeOAuthAuth(providerId, base, config, extension);
|
|
314
318
|
if (!apiKey && !oauth)
|
|
315
319
|
throw new Error(`Provider ${providerId}: no authentication method configured.`);
|
package/dist/core/sdk.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
-
import { Agent, setDefaultStreamFn } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import { Agent, createInternalAgentChannel, setDefaultStreamFn, } from "@earendil-works/pi-agent-core";
|
|
3
3
|
import { modelsAreEqual, streamSimple } from "@earendil-works/pi-ai/compat";
|
|
4
4
|
import { getAgentDir } from "../config.js";
|
|
5
5
|
import { resolvePath } from "../utils/paths.js";
|
|
@@ -283,7 +283,9 @@ export async function createAgentSession(options = {}) {
|
|
|
283
283
|
model: model.id,
|
|
284
284
|
});
|
|
285
285
|
};
|
|
286
|
+
const internalChannel = createInternalAgentChannel();
|
|
286
287
|
agent = new Agent({
|
|
288
|
+
internalChannel,
|
|
287
289
|
initialState: {
|
|
288
290
|
systemPrompt: "",
|
|
289
291
|
model,
|
|
@@ -382,6 +384,7 @@ export async function createAgentSession(options = {}) {
|
|
|
382
384
|
: options.sessionStartEvent;
|
|
383
385
|
const session = new AgentSession({
|
|
384
386
|
agent,
|
|
387
|
+
internalChannel,
|
|
385
388
|
serviceTier: options.serviceTier,
|
|
386
389
|
sessionManager,
|
|
387
390
|
settingsManager,
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* `AgentSession.isSessionBusy` instead of testing individual flags, so a source
|
|
17
17
|
* added later cannot be silently missed by one call site.
|
|
18
18
|
*/
|
|
19
|
+
import { normalizeWaitItems, wakeSourceItems } from "./lifecycle-wait-items.js";
|
|
19
20
|
/** Live counts of extension-published wake sources, keyed by source name. */
|
|
20
21
|
export class WakeSourceTracker {
|
|
21
22
|
constructor() {
|
|
@@ -39,6 +40,7 @@ export class WakeSourceTracker {
|
|
|
39
40
|
this.counts.set(source, {
|
|
40
41
|
activeCount,
|
|
41
42
|
kind: "kind" in data && data.kind === "children" ? "children" : "background",
|
|
43
|
+
...normalizeWaitItems(wakeSourceItems(data)),
|
|
42
44
|
});
|
|
43
45
|
else
|
|
44
46
|
this.counts.delete(source);
|
|
@@ -9,13 +9,26 @@ export interface HumanWait {
|
|
|
9
9
|
readonly childLabel?: string;
|
|
10
10
|
readonly since: string;
|
|
11
11
|
}
|
|
12
|
+
export interface LifecycleWaitItem {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly label?: string;
|
|
15
|
+
readonly startedAt?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface LifecycleWaitSource {
|
|
18
|
+
readonly source: string;
|
|
19
|
+
readonly activeCount: number;
|
|
20
|
+
readonly items?: readonly LifecycleWaitItem[];
|
|
21
|
+
readonly omittedItems?: number;
|
|
22
|
+
}
|
|
12
23
|
export interface LifecycleWaits {
|
|
13
24
|
readonly children: number;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
/** Named detail can be incomplete even without truncation: custody need not have a named report. */
|
|
26
|
+
readonly childSources?: readonly LifecycleWaitSource[];
|
|
27
|
+
readonly childReports?: readonly Pick<ChildLifecycleReport, "taskId" | "childSessionId" | "runEpoch" | "state" | "label" | "since">[];
|
|
28
|
+
readonly childReportsOmitted?: number;
|
|
29
|
+
readonly background: readonly (LifecycleWaitSource & {
|
|
17
30
|
readonly retryAtMs?: number;
|
|
18
|
-
}[];
|
|
31
|
+
})[];
|
|
19
32
|
readonly human: readonly HumanWait[];
|
|
20
33
|
}
|
|
21
34
|
export interface LifecycleHold {
|
|
@@ -83,6 +96,9 @@ export interface ChildLifecycleReport {
|
|
|
83
96
|
readonly runEpoch: number;
|
|
84
97
|
readonly generation: number;
|
|
85
98
|
readonly state: SessionLifecycleState;
|
|
99
|
+
readonly label?: string;
|
|
100
|
+
/** The child's own state-entry time, not the parent's evaluation time. */
|
|
101
|
+
readonly since?: string;
|
|
86
102
|
readonly waitingOn?: LifecycleWaits;
|
|
87
103
|
readonly terminal?: "completed" | "error" | "lost" | "interrupted" | "cancelled";
|
|
88
104
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { effectiveWakes } from "./extensions/builtin/goal/turn-end-liveness.js";
|
|
2
2
|
import { LifecycleChildren } from "./lifecycle-children.js";
|
|
3
3
|
import { LifecycleLedger } from "./lifecycle-ledger.js";
|
|
4
|
+
import { projectWaitItems } from "./lifecycle-wait-items.js";
|
|
4
5
|
import { sameStop, stopDetail } from "./lifecycle-stop.js";
|
|
5
6
|
import { lifecycleState, lifecycleTerminal } from "./session-lifecycle-reducer.js";
|
|
6
7
|
import { SessionWorkObligations } from "./work-obligations.js";
|
|
@@ -189,11 +190,34 @@ export class SessionLifecycleController {
|
|
|
189
190
|
evaluate() {
|
|
190
191
|
const runtime = this.options.readRuntime();
|
|
191
192
|
const active = this.obligations.active;
|
|
192
|
-
const childRecords = this.children.reports
|
|
193
|
+
const childRecords = this.children.reports
|
|
194
|
+
.filter((report) => report.childSessionId !== this.options.sessionId && report.terminal === undefined)
|
|
195
|
+
.sort((a, b) => (a.taskId < b.taskId ? -1 : a.taskId > b.taskId ? 1 : 0));
|
|
196
|
+
const childReports = childRecords
|
|
197
|
+
.slice(0, 32)
|
|
198
|
+
.map(({ taskId, childSessionId, runEpoch, state, label, since }) => ({
|
|
199
|
+
taskId,
|
|
200
|
+
childSessionId,
|
|
201
|
+
runEpoch,
|
|
202
|
+
state,
|
|
203
|
+
...(label === undefined ? {} : { label }),
|
|
204
|
+
...(since === undefined ? {} : { since }),
|
|
205
|
+
}));
|
|
206
|
+
const childSources = active
|
|
207
|
+
.filter((record) => record.kind === "children")
|
|
208
|
+
.map((record) => ({
|
|
209
|
+
source: record.source ?? record.key,
|
|
210
|
+
activeCount: record.activeCount ?? 1,
|
|
211
|
+
...projectWaitItems(record),
|
|
212
|
+
}));
|
|
193
213
|
const background = active
|
|
194
214
|
.filter((record) => record.kind === "background")
|
|
195
|
-
.map((record) => ({
|
|
196
|
-
|
|
215
|
+
.map((record) => ({
|
|
216
|
+
source: record.source ?? record.key,
|
|
217
|
+
activeCount: record.activeCount ?? 1,
|
|
218
|
+
...projectWaitItems(record),
|
|
219
|
+
}));
|
|
220
|
+
const children = Math.max(childRecords.length, active
|
|
197
221
|
.filter((record) => record.kind === "children")
|
|
198
222
|
.reduce((sum, record) => sum + (record.activeCount ?? 1), 0));
|
|
199
223
|
const input = this.liveness;
|
|
@@ -297,7 +321,14 @@ export class SessionLifecycleController {
|
|
|
297
321
|
runEpoch: this.ownTask.runEpoch,
|
|
298
322
|
}
|
|
299
323
|
: undefined;
|
|
300
|
-
const waits = {
|
|
324
|
+
const waits = {
|
|
325
|
+
children,
|
|
326
|
+
background,
|
|
327
|
+
human,
|
|
328
|
+
...(childSources.length ? { childSources } : {}),
|
|
329
|
+
...(childReports.length ? { childReports } : {}),
|
|
330
|
+
...(childRecords.length > 32 ? { childReportsOmitted: childRecords.length - 32 } : {}),
|
|
331
|
+
};
|
|
301
332
|
const lastStop = this.lastStop(input, synthetic.some((wait) => wait.kind === "stalled"));
|
|
302
333
|
const state = lifecycleState({
|
|
303
334
|
role: this.ledger.snapshot.role,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { InternalAgentChannel } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import { type AssistantProgress } from "@earendil-works/pi-ai";
|
|
3
|
+
import type { AgentSessionEvent } from "./agent-session.ts";
|
|
4
|
+
/** One record of a session's internal structured lane: a session event or a block control, in session order. */
|
|
5
|
+
export type AgentSessionStructuredRecord = AgentSessionEvent | AssistantProgress;
|
|
6
|
+
type StructuredListener = (record: AgentSessionStructuredRecord) => void;
|
|
7
|
+
export declare class StructuredLaneUnavailableError extends Error {
|
|
8
|
+
constructor();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The AgentSession end of the internal-only agent channel (senpi#4272, R3.C6.2). While a structured listener is
|
|
12
|
+
* attached, it holds the channel's capture subscription; block controls enter the session's own event queue, so they
|
|
13
|
+
* keep their position among the ordinary events. Extension listeners, `session.subscribe` and every legacy
|
|
14
|
+
* destination never see a control.
|
|
15
|
+
*
|
|
16
|
+
* The capture subscription is module-wide (`subscribeAssistantCapture`): while it is held, every capture-enabled
|
|
17
|
+
* provider stream in the process that first pushes afterwards builds capture records, including streams of sessions
|
|
18
|
+
* with no structured listener, which drop them at their public iterator.
|
|
19
|
+
*/
|
|
20
|
+
export declare class StructuredSessionLane {
|
|
21
|
+
#private;
|
|
22
|
+
private readonly listeners;
|
|
23
|
+
private releaseChannel;
|
|
24
|
+
constructor(channel: InternalAgentChannel | undefined, enqueue: (deliver: () => void) => void);
|
|
25
|
+
get active(): boolean;
|
|
26
|
+
subscribe(listener: StructuredListener): () => void;
|
|
27
|
+
/** Publishes a session event with the provider capture of its `source` agent event. */
|
|
28
|
+
emitEvent(event: AgentSessionEvent, source: object): void;
|
|
29
|
+
dispose(): void;
|
|
30
|
+
private emit;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=structured-session-lane.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { carryAssistantCapture } from "@earendil-works/pi-ai";
|
|
2
|
+
export class StructuredLaneUnavailableError extends Error {
|
|
3
|
+
constructor() {
|
|
4
|
+
super("Structured lane unavailable: Agent was constructed outside the session layer");
|
|
5
|
+
this.name = "StructuredLaneUnavailableError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The AgentSession end of the internal-only agent channel (senpi#4272, R3.C6.2). While a structured listener is
|
|
10
|
+
* attached, it holds the channel's capture subscription; block controls enter the session's own event queue, so they
|
|
11
|
+
* keep their position among the ordinary events. Extension listeners, `session.subscribe` and every legacy
|
|
12
|
+
* destination never see a control.
|
|
13
|
+
*
|
|
14
|
+
* The capture subscription is module-wide (`subscribeAssistantCapture`): while it is held, every capture-enabled
|
|
15
|
+
* provider stream in the process that first pushes afterwards builds capture records, including streams of sessions
|
|
16
|
+
* with no structured listener, which drop them at their public iterator.
|
|
17
|
+
*/
|
|
18
|
+
export class StructuredSessionLane {
|
|
19
|
+
#channel;
|
|
20
|
+
#enqueue;
|
|
21
|
+
constructor(channel, enqueue) {
|
|
22
|
+
this.listeners = new Set();
|
|
23
|
+
this.#channel = channel;
|
|
24
|
+
this.#enqueue = enqueue;
|
|
25
|
+
}
|
|
26
|
+
get active() {
|
|
27
|
+
return this.listeners.size > 0;
|
|
28
|
+
}
|
|
29
|
+
subscribe(listener) {
|
|
30
|
+
if (!this.#channel)
|
|
31
|
+
throw new StructuredLaneUnavailableError();
|
|
32
|
+
this.listeners.add(listener);
|
|
33
|
+
this.releaseChannel ??= this.#channel.subscribe((record) => {
|
|
34
|
+
if ("progress" in record)
|
|
35
|
+
this.#enqueue(() => this.emit(record.progress));
|
|
36
|
+
});
|
|
37
|
+
return () => {
|
|
38
|
+
this.listeners.delete(listener);
|
|
39
|
+
if (this.listeners.size === 0)
|
|
40
|
+
this.dispose();
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Publishes a session event with the provider capture of its `source` agent event. */
|
|
44
|
+
emitEvent(event, source) {
|
|
45
|
+
const message = (event.type === "message_start" || event.type === "message_end") && event.message.role === "assistant"
|
|
46
|
+
? event.message
|
|
47
|
+
: undefined;
|
|
48
|
+
// A user-facing description replaced the engine message, so the capture's frozen message must follow it.
|
|
49
|
+
const described = message && "message" in source && source.message !== message ? message : undefined;
|
|
50
|
+
this.emit(carryAssistantCapture(source, event, described));
|
|
51
|
+
}
|
|
52
|
+
dispose() {
|
|
53
|
+
this.listeners.clear();
|
|
54
|
+
this.releaseChannel?.();
|
|
55
|
+
this.releaseChannel = undefined;
|
|
56
|
+
}
|
|
57
|
+
emit(record) {
|
|
58
|
+
for (const listener of [...this.listeners])
|
|
59
|
+
listener(record);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=structured-session-lane.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CustomMessage } from "./messages.ts";
|
|
2
|
+
import { type WaitSourceItems } from "./lifecycle-wait-items.ts";
|
|
2
3
|
import type { ObligationKind } from "./session-lifecycle-types.ts";
|
|
3
4
|
export interface CustodyPayload {
|
|
4
5
|
readonly message: Pick<CustomMessage, "customType" | "content" | "display" | "details">;
|
|
@@ -7,7 +8,7 @@ export interface CustodyPayload {
|
|
|
7
8
|
readonly itemIds?: readonly string[];
|
|
8
9
|
}
|
|
9
10
|
/** Mutable only by the registry; every replacement is appended before installation. */
|
|
10
|
-
export interface WorkCustodyRecord {
|
|
11
|
+
export interface WorkCustodyRecord extends WaitSourceItems {
|
|
11
12
|
readonly id: string;
|
|
12
13
|
readonly key: string;
|
|
13
14
|
readonly kind: ObligationKind;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeWaitItems } from "./lifecycle-wait-items.js";
|
|
1
2
|
export function isRecord(value) {
|
|
2
3
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
4
|
}
|
|
@@ -25,6 +26,7 @@ export function readWorkCustody(value) {
|
|
|
25
26
|
key: value.key,
|
|
26
27
|
kind: value.kind,
|
|
27
28
|
state: value.state,
|
|
29
|
+
...normalizeWaitItems(value.items, value.omittedItems),
|
|
28
30
|
...(typeof value.source === "string" ? { source: value.source } : {}),
|
|
29
31
|
...(typeof value.activeCount === "number" ? { activeCount: value.activeCount } : {}),
|
|
30
32
|
...(typeof value.detail === "string" ? { detail: value.detail } : {}),
|
|
@@ -36,7 +36,7 @@ export declare class SessionWorkObligations implements WorkObligations {
|
|
|
36
36
|
get activeCount(): number;
|
|
37
37
|
get persisted(): boolean;
|
|
38
38
|
open(key: string, kind: ObligationKind, detail?: string): ObligationToken;
|
|
39
|
-
syncSource(source: string, kind: ObligationKind, activeCount: number): void;
|
|
39
|
+
syncSource(source: string, kind: ObligationKind, activeCount: number, items?: unknown): void;
|
|
40
40
|
/** After a restart, a restored wake source stays open only if its producer published again. */
|
|
41
41
|
retireRestoredSources(): void;
|
|
42
42
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeWaitItems, waitItemSignature } from "./lifecycle-wait-items.js";
|
|
1
2
|
import { custodyIsOpen, readWorkCustody } from "./work-custody-record.js";
|
|
2
3
|
/** Custody keys the engine opens itself (senpi#3986): queued deliveries and published wake sources. */
|
|
3
4
|
export const ENGINE_DELIVERY_KEY_PREFIX = "delivery:";
|
|
@@ -59,7 +60,7 @@ export class SessionWorkObligations {
|
|
|
59
60
|
this.store.changed();
|
|
60
61
|
return this.token(record.id);
|
|
61
62
|
}
|
|
62
|
-
syncSource(source, kind, activeCount) {
|
|
63
|
+
syncSource(source, kind, activeCount, items) {
|
|
63
64
|
const key = `${WAKE_SOURCE_KEY_PREFIX}${source}`;
|
|
64
65
|
this.publishedSources.add(key);
|
|
65
66
|
const current = this.active.find((record) => record.key === key);
|
|
@@ -68,7 +69,10 @@ export class SessionWorkObligations {
|
|
|
68
69
|
this.close(current.id, "passive");
|
|
69
70
|
return;
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
+
const detail = normalizeWaitItems(items);
|
|
73
|
+
if (current?.activeCount === activeCount &&
|
|
74
|
+
current.kind === kind &&
|
|
75
|
+
waitItemSignature(current) === waitItemSignature(detail))
|
|
72
76
|
return;
|
|
73
77
|
this.install({
|
|
74
78
|
...current,
|
|
@@ -77,6 +81,8 @@ export class SessionWorkObligations {
|
|
|
77
81
|
source,
|
|
78
82
|
kind,
|
|
79
83
|
activeCount,
|
|
84
|
+
items: detail.items,
|
|
85
|
+
omittedItems: detail.omittedItems,
|
|
80
86
|
state: current?.state ?? "open",
|
|
81
87
|
});
|
|
82
88
|
this.store.changed();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AssistantMessage, getAssistantCapture, type TextContent, type ThinkingContent, type ToolCall, type Usage } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { AgentSessionEvent } from "../core/agent-session.ts";
|
|
3
3
|
type WithoutPartial<T> = T extends {
|
|
4
4
|
partial: unknown;
|
|
@@ -13,6 +13,7 @@ type ToJsonAssistantMessageEvent<T> = T extends {
|
|
|
13
13
|
type MessageUpdateEvent = Extract<AgentSessionEvent, {
|
|
14
14
|
type: "message_update";
|
|
15
15
|
}>;
|
|
16
|
+
type AssistantCapture = NonNullable<ReturnType<typeof getAssistantCapture>>;
|
|
16
17
|
type JsonMessageUpdateEvent = {
|
|
17
18
|
type: "message_update";
|
|
18
19
|
usage: Usage;
|
|
@@ -23,6 +24,82 @@ type JsonMessageUpdateEvent = {
|
|
|
23
24
|
export type JsonAgentSessionEvent = Exclude<AgentSessionEvent, {
|
|
24
25
|
type: "message_update";
|
|
25
26
|
}> | JsonMessageUpdateEvent;
|
|
27
|
+
/** The engine-staged block-seed projection (senpi#4272, R3.C6.2); no public destination selects it before S17. */
|
|
28
|
+
export interface BlockSeedOptions {
|
|
29
|
+
readonly blockSeeds: 1;
|
|
30
|
+
}
|
|
31
|
+
type SeededAssistantEvent = {
|
|
32
|
+
type: "start";
|
|
33
|
+
seed: {
|
|
34
|
+
message: AssistantMessage;
|
|
35
|
+
};
|
|
36
|
+
} | {
|
|
37
|
+
type: "text_start";
|
|
38
|
+
contentIndex: number;
|
|
39
|
+
seed: {
|
|
40
|
+
block: TextContent;
|
|
41
|
+
coveredCodeUnits: number;
|
|
42
|
+
};
|
|
43
|
+
} | {
|
|
44
|
+
type: "thinking_start";
|
|
45
|
+
contentIndex: number;
|
|
46
|
+
seed: {
|
|
47
|
+
block: ThinkingContent;
|
|
48
|
+
coveredCodeUnits: number;
|
|
49
|
+
};
|
|
50
|
+
} | {
|
|
51
|
+
type: "toolcall_start";
|
|
52
|
+
contentIndex: number;
|
|
53
|
+
id: string;
|
|
54
|
+
toolName: string;
|
|
55
|
+
seed: {
|
|
56
|
+
block: ToolCall;
|
|
57
|
+
rawArgumentPrefix: string;
|
|
58
|
+
parsedThrough: number;
|
|
59
|
+
coveredCodeUnits: number;
|
|
60
|
+
};
|
|
61
|
+
} | {
|
|
62
|
+
type: "text_delta" | "thinking_delta";
|
|
63
|
+
contentIndex: number;
|
|
64
|
+
delta: string;
|
|
65
|
+
offset: number;
|
|
66
|
+
} | {
|
|
67
|
+
type: "toolcall_delta";
|
|
68
|
+
contentIndex: number;
|
|
69
|
+
delta: string;
|
|
70
|
+
offset: number;
|
|
71
|
+
parsedThrough: number;
|
|
72
|
+
} | {
|
|
73
|
+
type: "text_end";
|
|
74
|
+
contentIndex: number;
|
|
75
|
+
content: string;
|
|
76
|
+
block: TextContent;
|
|
77
|
+
} | {
|
|
78
|
+
type: "thinking_end";
|
|
79
|
+
contentIndex: number;
|
|
80
|
+
content: string;
|
|
81
|
+
block: ThinkingContent;
|
|
82
|
+
} | {
|
|
83
|
+
type: "toolcall_end";
|
|
84
|
+
contentIndex: number;
|
|
85
|
+
toolCall: ToolCall;
|
|
86
|
+
} | {
|
|
87
|
+
type: "done";
|
|
88
|
+
reason: string;
|
|
89
|
+
message: AssistantMessage;
|
|
90
|
+
} | {
|
|
91
|
+
type: "error";
|
|
92
|
+
reason: string;
|
|
93
|
+
error: AssistantMessage;
|
|
94
|
+
};
|
|
95
|
+
export type SeededJsonMessageUpdateEvent = Omit<MessageUpdateEvent, "message" | "assistantMessageEvent"> & {
|
|
96
|
+
usage: Usage;
|
|
97
|
+
messageMetadata?: AssistantCapture["metadata"];
|
|
98
|
+
assistantMessageEvent: SeededAssistantEvent;
|
|
99
|
+
};
|
|
100
|
+
export type SeededJsonAgentSessionEvent = Exclude<AgentSessionEvent, {
|
|
101
|
+
type: "message_update";
|
|
102
|
+
}> | SeededJsonMessageUpdateEvent;
|
|
26
103
|
/**
|
|
27
104
|
* Remove cumulative assistant snapshots from streaming wire events.
|
|
28
105
|
* `message_start` provides the initial message, deltas build it, and
|
|
@@ -31,5 +108,6 @@ export type JsonAgentSessionEvent = Exclude<AgentSessionEvent, {
|
|
|
31
108
|
*/
|
|
32
109
|
export declare function toJsonEvent(event: MessageUpdateEvent): JsonMessageUpdateEvent;
|
|
33
110
|
export declare function toJsonEvent(event: AgentSessionEvent): JsonAgentSessionEvent;
|
|
111
|
+
export declare function toJsonEvent(event: AgentSessionEvent, options: BlockSeedOptions): SeededJsonAgentSessionEvent | undefined;
|
|
34
112
|
export {};
|
|
35
113
|
//# sourceMappingURL=json-event.d.ts.map
|