pi-background-tasks 2.5.0 → 2.6.0
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/BACKGROUND-TASKS-INSTRUCTIONS.md +1 -1
- package/README.md +70 -25
- package/TESTING.md +42 -2
- package/TEST_PLAN.md +7 -4
- package/dist/extensions/anthropic-attribution-child.js +4 -0
- package/dist/extensions/anthropic-attribution-child.js.map +1 -0
- package/dist/extensions/anthropic-attribution.js +107 -0
- package/dist/extensions/anthropic-attribution.js.map +1 -0
- package/dist/extensions/background-tasks.js +2 -0
- package/dist/extensions/background-tasks.js.map +1 -0
- package/dist/extensions/delegate-child.js +2 -0
- package/dist/extensions/delegate-child.js.map +1 -0
- package/dist/extensions/fusion-child.js +2 -0
- package/dist/extensions/fusion-child.js.map +1 -0
- package/dist/package.json +5 -0
- package/dist/src/core/anthropic-attribution-path.js +24 -0
- package/dist/src/core/anthropic-attribution-path.js.map +1 -0
- package/dist/src/core/anthropic-attribution.js +2247 -0
- package/dist/src/core/anthropic-attribution.js.map +1 -0
- package/dist/src/core/attested-pi-contract.js +5 -0
- package/dist/src/core/attested-pi-contract.js.map +1 -0
- package/dist/src/core/attested-pi-run.js +749 -0
- package/dist/src/core/attested-pi-run.js.map +1 -0
- package/dist/src/core/canonical-json.js +19 -0
- package/dist/src/core/canonical-json.js.map +1 -0
- package/dist/src/core/common.js +787 -0
- package/dist/src/core/common.js.map +1 -0
- package/dist/src/core/config.js +78 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/context/parent-snapshot.js +75 -0
- package/dist/src/core/context/parent-snapshot.js.map +1 -0
- package/dist/src/core/context/token-budget.js +631 -0
- package/dist/src/core/context/token-budget.js.map +1 -0
- package/dist/src/core/context/visible-conversation-v2.js +390 -0
- package/dist/src/core/context/visible-conversation-v2.js.map +1 -0
- package/dist/src/core/delegate/artifacts.js +357 -0
- package/dist/src/core/delegate/artifacts.js.map +1 -0
- package/dist/src/core/delegate/budget.js +266 -0
- package/dist/src/core/delegate/budget.js.map +1 -0
- package/dist/src/core/delegate/facade-contract.js +7 -0
- package/dist/src/core/delegate/facade-contract.js.map +1 -0
- package/dist/src/core/delegate/hook-contract-evidence.json +18 -0
- package/dist/src/core/delegate/hook-contract.js +124 -0
- package/dist/src/core/delegate/hook-contract.js.map +1 -0
- package/dist/src/core/delegate/launch.js +366 -0
- package/dist/src/core/delegate/launch.js.map +1 -0
- package/dist/src/core/delegate/result-package.js +293 -0
- package/dist/src/core/delegate/result-package.js.map +1 -0
- package/dist/src/core/delegate/runner.js +398 -0
- package/dist/src/core/delegate/runner.js.map +1 -0
- package/dist/src/core/delegate/seed.js +334 -0
- package/dist/src/core/delegate/seed.js.map +1 -0
- package/dist/src/core/delegate/types.js +103 -0
- package/dist/src/core/delegate/types.js.map +1 -0
- package/dist/src/core/durable-fs.js +372 -0
- package/dist/src/core/durable-fs.js.map +1 -0
- package/dist/src/core/extension-api.js +382 -0
- package/dist/src/core/extension-api.js.map +1 -0
- package/dist/src/core/fusion/artifacts.js +654 -0
- package/dist/src/core/fusion/artifacts.js.map +1 -0
- package/dist/src/core/fusion/budget.js +949 -0
- package/dist/src/core/fusion/budget.js.map +1 -0
- package/dist/src/core/fusion/child-protocol.js +176 -0
- package/dist/src/core/fusion/child-protocol.js.map +1 -0
- package/dist/src/core/fusion/claude-cache.js +156 -0
- package/dist/src/core/fusion/claude-cache.js.map +1 -0
- package/dist/src/core/fusion/clean-context.js +64 -0
- package/dist/src/core/fusion/clean-context.js.map +1 -0
- package/dist/src/core/fusion/config.js +349 -0
- package/dist/src/core/fusion/config.js.map +1 -0
- package/dist/src/core/fusion/context.js +184 -0
- package/dist/src/core/fusion/context.js.map +1 -0
- package/dist/src/core/fusion/evaluation.js +696 -0
- package/dist/src/core/fusion/evaluation.js.map +1 -0
- package/dist/src/core/fusion/facade-contract.js +3 -0
- package/dist/src/core/fusion/facade-contract.js.map +1 -0
- package/dist/src/core/fusion/orchestrator.js +867 -0
- package/dist/src/core/fusion/orchestrator.js.map +1 -0
- package/dist/src/core/fusion/output-contract.js +27 -0
- package/dist/src/core/fusion/output-contract.js.map +1 -0
- package/dist/src/core/fusion/pi-child.js +1741 -0
- package/dist/src/core/fusion/pi-child.js.map +1 -0
- package/dist/src/core/fusion/prompts.js +260 -0
- package/dist/src/core/fusion/prompts.js.map +1 -0
- package/dist/src/core/fusion/result-package.js +857 -0
- package/dist/src/core/fusion/result-package.js.map +1 -0
- package/dist/src/core/fusion/source-policy.js +259 -0
- package/dist/src/core/fusion/source-policy.js.map +1 -0
- package/dist/src/core/fusion/types.js +207 -0
- package/dist/src/core/fusion/types.js.map +1 -0
- package/dist/src/core/fusion/web-fetch.js +777 -0
- package/dist/src/core/fusion/web-fetch.js.map +1 -0
- package/dist/src/core/fusion/workflows.js +126 -0
- package/dist/src/core/fusion/workflows.js.map +1 -0
- package/dist/src/core/lazy-module.js +181 -0
- package/dist/src/core/lazy-module.js.map +1 -0
- package/dist/src/core/pi-launch.js +431 -0
- package/dist/src/core/pi-launch.js.map +1 -0
- package/dist/src/core/registry.js +3331 -0
- package/dist/src/core/registry.js.map +1 -0
- package/dist/src/core/reload-shell-owner.js +1396 -0
- package/dist/src/core/reload-shell-owner.js.map +1 -0
- package/dist/src/core/shell-policy.js +80 -0
- package/dist/src/core/shell-policy.js.map +1 -0
- package/dist/src/core/task-durable.js +51 -0
- package/dist/src/core/task-durable.js.map +1 -0
- package/dist/src/core/update-check.js +92 -0
- package/dist/src/core/update-check.js.map +1 -0
- package/dist/src/core/windows-taskkill.js +185 -0
- package/dist/src/core/windows-taskkill.js.map +1 -0
- package/dist/src/delegate-child-extension.js +776 -0
- package/dist/src/delegate-child-extension.js.map +1 -0
- package/dist/src/delegate-extension.js +746 -0
- package/dist/src/delegate-extension.js.map +1 -0
- package/dist/src/extension.js +953 -0
- package/dist/src/extension.js.map +1 -0
- package/dist/src/fusion-child-extension.js +760 -0
- package/dist/src/fusion-child-extension.js.map +1 -0
- package/dist/src/fusion-extension.js +1030 -0
- package/dist/src/fusion-extension.js.map +1 -0
- package/dist/src/ui/background-tasks-manager.js +689 -0
- package/dist/src/ui/background-tasks-manager.js.map +1 -0
- package/dist/src/ui/fusion-model-selector.js +277 -0
- package/dist/src/ui/fusion-model-selector.js.map +1 -0
- package/docs/INDEX.md +35 -33
- package/docs/api/eventbus-v1.md +21 -5
- package/docs/choose-a-workflow.md +2 -0
- package/docs/commands/bg-clear.md +3 -3
- package/docs/commands/bg-update.md +3 -3
- package/docs/commands/bg.md +18 -6
- package/docs/commands/claude-cache.md +4 -4
- package/docs/commands/fusion-models.md +49 -4
- package/docs/commands/fusion.md +3 -3
- package/docs/commands/jobs.md +3 -3
- package/docs/commands/kill.md +3 -3
- package/docs/commands/logs.md +3 -3
- package/docs/commands/task-manager.md +5 -5
- package/docs/concepts/completion-delivery.md +6 -2
- package/docs/getting-started.md +7 -1
- package/docs/manifest.json +228 -42
- package/docs/operations/configuration.md +58 -5
- package/docs/operations/releasing.md +4 -2
- package/docs/operations/testing.md +22 -0
- package/docs/operations/troubleshooting.md +6 -2
- package/docs/read-before-edit.md +44 -31
- package/docs/reference/runtime-contracts.md +87 -51
- package/docs/reference/shortcuts-and-dock.md +28 -14
- package/docs/subsystems/anthropic-attribution.md +23 -11
- package/docs/subsystems/attested-pi-runs.md +12 -7
- package/docs/subsystems/background-task-runtime.md +53 -11
- package/docs/subsystems/child-launch-durability-and-safety.md +28 -9
- package/docs/subsystems/delegation.md +16 -3
- package/docs/subsystems/docs-freshness-gate.md +14 -7
- package/docs/subsystems/fusion.md +36 -11
- package/docs/subsystems/host-ui-and-telemetry.md +22 -9
- package/docs/tools/bg_delegate.md +3 -1
- package/docs/tools/bg_kill.md +3 -1
- package/docs/tools/bg_logs.md +3 -1
- package/docs/tools/bg_result.md +5 -3
- package/docs/tools/bg_run.md +31 -5
- package/docs/tools/bg_run_pi_attested.md +3 -1
- package/docs/tools/bg_status.md +3 -1
- package/docs/tools/fusion_investigate.md +3 -1
- package/docs/tools/fusion_reason.md +3 -1
- package/docs/tools/fusion_research.md +3 -1
- package/docs/tools/fusion_validate.md +3 -1
- package/extensions/anthropic-attribution-child.ts +3 -0
- package/extensions/anthropic-attribution.ts +166 -1
- package/package.json +12 -10
- package/src/core/anthropic-attribution-path.ts +5 -4
- package/src/core/anthropic-attribution.ts +293 -113
- package/src/core/attested-pi-contract.ts +4 -0
- package/src/core/attested-pi-run.ts +468 -81
- package/src/core/canonical-json.ts +21 -0
- package/src/core/common.ts +450 -40
- package/src/core/config.ts +121 -0
- package/src/core/context/visible-conversation-v2.ts +3 -6
- package/src/core/delegate/artifacts.ts +13 -9
- package/src/core/delegate/budget.ts +13 -6
- package/src/core/delegate/facade-contract.ts +6 -0
- package/src/core/delegate/result-package.ts +32 -14
- package/src/core/delegate/runner.ts +129 -58
- package/src/core/delegate/seed.ts +5 -7
- package/src/core/durable-fs.ts +178 -30
- package/src/core/extension-api.ts +36 -8
- package/src/core/fusion/artifacts.ts +17 -16
- package/src/core/fusion/clean-context.ts +8 -5
- package/src/core/fusion/config.ts +2 -1
- package/src/core/fusion/context.ts +2 -6
- package/src/core/fusion/facade-contract.ts +2 -0
- package/src/core/fusion/orchestrator.ts +3 -3
- package/src/core/fusion/prompts.ts +1 -1
- package/src/core/fusion/result-package.ts +259 -72
- package/src/core/fusion/source-policy.ts +43 -17
- package/src/core/lazy-module.ts +215 -0
- package/src/core/pi-launch.ts +390 -65
- package/src/core/registry.ts +2010 -381
- package/src/core/reload-shell-owner.ts +1662 -0
- package/src/core/shell-policy.ts +134 -0
- package/src/core/task-durable.ts +67 -0
- package/src/delegate-extension.ts +404 -144
- package/src/extension.ts +387 -114
- package/src/fusion-extension.ts +202 -96
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { appendFileSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
4
|
+
import { isAbsolute, join } from 'node:path';
|
|
5
|
+
import { anthropicMessagesApi } from '@earendil-works/pi-ai/compat';
|
|
6
|
+
import type {
|
|
7
|
+
AssistantMessageEventStream as HostAssistantMessageEventStream,
|
|
8
|
+
Context as HostContext,
|
|
9
|
+
Model as HostModel,
|
|
10
|
+
SimpleStreamOptions as HostSimpleStreamOptions,
|
|
11
|
+
} from '@earendil-works/pi-ai';
|
|
5
12
|
|
|
6
13
|
export const CLAUDE_CODE_SESSION_HEADER = 'X-Claude-Code-Session-Id';
|
|
7
14
|
|
|
@@ -72,6 +79,7 @@ const CLAUDE_AGENT_SDK_SYSTEM_TEXT =
|
|
|
72
79
|
const FINGERPRINT_SALT = '59cf53e54c78';
|
|
73
80
|
const AUDIT_ENV = 'PIPELINE_ANTHROPIC_ATTRIBUTION_AUDIT_PATH';
|
|
74
81
|
const CACHE_RETENTION_ENV = 'PI_CACHE_RETENTION';
|
|
82
|
+
export const ANTHROPIC_ACCOUNT_CONFIG_PATH_ENV = 'PI_ANTHROPIC_ACCOUNT_CONFIG_PATH';
|
|
75
83
|
export const ANTHROPIC_CACHE_RETENTION_ENTRY = 'pipeline-anthropic-cache-retention';
|
|
76
84
|
const ANTHROPIC_CACHE_RETENTION_SCHEMA = 'pipeline.anthropic_cache_retention.v1';
|
|
77
85
|
export const ANTHROPIC_ATTRIBUTION_CLAIM_CHANNEL = 'pi-anthropic-attribution:claim:v1';
|
|
@@ -146,8 +154,11 @@ interface PiModelCostLike extends PiCostRatesLike {
|
|
|
146
154
|
export interface PiModelLike {
|
|
147
155
|
readonly provider?: string;
|
|
148
156
|
readonly id?: string;
|
|
157
|
+
readonly name?: string;
|
|
149
158
|
readonly api?: string;
|
|
150
159
|
readonly baseUrl?: string;
|
|
160
|
+
readonly input?: readonly ('text' | 'image')[];
|
|
161
|
+
readonly contextWindow?: number;
|
|
151
162
|
readonly maxTokens?: number;
|
|
152
163
|
readonly reasoning?: boolean;
|
|
153
164
|
readonly compat?: {
|
|
@@ -394,7 +405,11 @@ interface PiAssistantDiagnosticLike {
|
|
|
394
405
|
}
|
|
395
406
|
|
|
396
407
|
type PiMessage =
|
|
397
|
-
| {
|
|
408
|
+
| {
|
|
409
|
+
readonly role: 'user';
|
|
410
|
+
readonly content: string | readonly PiContentBlock[];
|
|
411
|
+
readonly timestamp?: number;
|
|
412
|
+
}
|
|
398
413
|
| {
|
|
399
414
|
readonly role: 'assistant';
|
|
400
415
|
readonly content: readonly JsonObject[];
|
|
@@ -404,6 +419,7 @@ type PiMessage =
|
|
|
404
419
|
readonly responseId?: string;
|
|
405
420
|
readonly stopReason?: string;
|
|
406
421
|
readonly diagnostics?: readonly PiAssistantDiagnosticLike[];
|
|
422
|
+
readonly timestamp?: number;
|
|
407
423
|
}
|
|
408
424
|
| {
|
|
409
425
|
readonly role: 'toolResult';
|
|
@@ -411,6 +427,7 @@ type PiMessage =
|
|
|
411
427
|
readonly toolName?: string;
|
|
412
428
|
readonly content: readonly PiContentBlock[];
|
|
413
429
|
readonly isError?: boolean;
|
|
430
|
+
readonly timestamp?: number;
|
|
414
431
|
};
|
|
415
432
|
|
|
416
433
|
export interface PiStreamContext {
|
|
@@ -465,14 +482,20 @@ export interface AssistantMessageLike {
|
|
|
465
482
|
cacheRead: number;
|
|
466
483
|
cacheWrite: number;
|
|
467
484
|
cacheWrite1h?: number;
|
|
485
|
+
reasoning?: number;
|
|
468
486
|
totalTokens: number;
|
|
469
487
|
cost: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number };
|
|
470
488
|
};
|
|
471
|
-
stopReason: 'stop' | 'length' | 'toolUse' | 'aborted' | 'error';
|
|
489
|
+
stopReason: 'pending' | 'stop' | 'length' | 'toolUse' | 'aborted' | 'error' | 'deferred';
|
|
472
490
|
timestamp: number;
|
|
491
|
+
responseModel?: string;
|
|
473
492
|
responseId?: string;
|
|
493
|
+
providerThinkingLevel?: string;
|
|
494
|
+
endTurn?: boolean;
|
|
474
495
|
diagnostics?: PiAssistantDiagnosticLike[];
|
|
496
|
+
deferred?: unknown;
|
|
475
497
|
errorMessage?: string;
|
|
498
|
+
rawStopReason?: string;
|
|
476
499
|
}
|
|
477
500
|
|
|
478
501
|
type AssistantMessageEvent =
|
|
@@ -862,20 +885,43 @@ export function extractClaudeAttributionAccount(
|
|
|
862
885
|
};
|
|
863
886
|
}
|
|
864
887
|
|
|
888
|
+
export function resolveClaudeAttributionConfigPath(
|
|
889
|
+
explicitConfigPath?: string,
|
|
890
|
+
env?: ProviderEnv,
|
|
891
|
+
homeDirectory = homedir(),
|
|
892
|
+
): string {
|
|
893
|
+
const configuredPath = providerEnvValue(ANTHROPIC_ACCOUNT_CONFIG_PATH_ENV, env);
|
|
894
|
+
const selectedPath = explicitConfigPath ?? configuredPath ?? join(homeDirectory, '.claude.json');
|
|
895
|
+
const source =
|
|
896
|
+
explicitConfigPath !== undefined
|
|
897
|
+
? 'explicit configPath'
|
|
898
|
+
: configuredPath !== undefined
|
|
899
|
+
? ANTHROPIC_ACCOUNT_CONFIG_PATH_ENV
|
|
900
|
+
: 'default ~/.claude.json path';
|
|
901
|
+
if (selectedPath.trim().length === 0 || !isAbsolute(selectedPath)) {
|
|
902
|
+
throw new Error(
|
|
903
|
+
`Anthropic attribution ${source} must be a non-empty absolute file path; got ${JSON.stringify(selectedPath)}`,
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
return selectedPath;
|
|
907
|
+
}
|
|
908
|
+
|
|
865
909
|
export function loadClaudeAttributionAccount(
|
|
866
|
-
configPath
|
|
910
|
+
configPath?: string,
|
|
911
|
+
env?: ProviderEnv,
|
|
867
912
|
): ClaudeAttributionAccount {
|
|
913
|
+
const selectedPath = resolveClaudeAttributionConfigPath(configPath, env);
|
|
868
914
|
let configText: string;
|
|
869
915
|
try {
|
|
870
|
-
configText = readFileSync(
|
|
916
|
+
configText = readFileSync(selectedPath, 'utf8');
|
|
871
917
|
} catch (error) {
|
|
872
918
|
throw new Error(
|
|
873
|
-
`Anthropic attribution config ${
|
|
919
|
+
`Anthropic attribution config ${selectedPath} could not be read: ${error instanceof Error ? error.message : String(error)}`,
|
|
874
920
|
);
|
|
875
921
|
}
|
|
876
922
|
return extractClaudeAttributionAccount(
|
|
877
|
-
parseJsonValue(configText, `Anthropic attribution config ${
|
|
878
|
-
|
|
923
|
+
parseJsonValue(configText, `Anthropic attribution config ${selectedPath}`),
|
|
924
|
+
selectedPath,
|
|
879
925
|
);
|
|
880
926
|
}
|
|
881
927
|
|
|
@@ -1414,6 +1460,10 @@ function isSha256(value: unknown): value is string {
|
|
|
1414
1460
|
return typeof value === 'string' && /^[a-f0-9]{64}$/u.test(value);
|
|
1415
1461
|
}
|
|
1416
1462
|
|
|
1463
|
+
function isNonEmptyString(value: unknown): value is string {
|
|
1464
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1417
1467
|
function blockWithoutCacheControl(block: unknown): unknown {
|
|
1418
1468
|
if (!isPlainObject(block)) return block;
|
|
1419
1469
|
const output = { ...block };
|
|
@@ -1466,31 +1516,82 @@ function parseAnthropicLineageDetails(
|
|
|
1466
1516
|
.find((candidate) => candidate.type === ANTHROPIC_LINEAGE_DIAGNOSTIC_TYPE);
|
|
1467
1517
|
const details = diagnostic?.details;
|
|
1468
1518
|
if (!isPlainObject(details)) return undefined;
|
|
1519
|
+
|
|
1520
|
+
const sourceModel = details['source_model'];
|
|
1521
|
+
const responseId = details['response_id'];
|
|
1522
|
+
const assistantContentSha256 = details['assistant_content_sha256'];
|
|
1523
|
+
const conversationStaticSha256 = details['conversation_static_sha256'];
|
|
1524
|
+
const requestMessageCount = details['request_message_count'];
|
|
1525
|
+
const requestMessagesSha256 = details['request_messages_sha256'];
|
|
1526
|
+
const cacheProfileSha256 = details['cache_profile_sha256'];
|
|
1527
|
+
const cacheRetention = details['cache_retention'];
|
|
1528
|
+
const compactionBoundarySha256 = details['compaction_boundary_sha256'];
|
|
1529
|
+
const signatureEpochSha256 = details['signature_epoch_sha256'];
|
|
1530
|
+
const signatureEpochInheritsPrior = details['signature_epoch_inherits_prior'];
|
|
1531
|
+
const previousMessageId = details['previous_message_id'];
|
|
1469
1532
|
if (
|
|
1470
1533
|
details['schema_version'] !== ANTHROPIC_LINEAGE_SCHEMA ||
|
|
1471
1534
|
details['projection_version'] !== ANTHROPIC_PROJECTION_VERSION ||
|
|
1472
1535
|
details['source_provider'] !== 'anthropic' ||
|
|
1473
1536
|
details['source_api'] !== 'anthropic-messages' ||
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
!isSha256(
|
|
1477
|
-
!isSha256(
|
|
1478
|
-
|
|
1479
|
-
(
|
|
1480
|
-
|
|
1481
|
-
!isSha256(
|
|
1482
|
-
(
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
(
|
|
1486
|
-
|
|
1487
|
-
!
|
|
1488
|
-
typeof details['signature_epoch_inherits_prior'] !== 'boolean' ||
|
|
1489
|
-
(details['previous_message_id'] !== null && typeof details['previous_message_id'] !== 'string')
|
|
1537
|
+
!isNonEmptyString(sourceModel) ||
|
|
1538
|
+
!isNonEmptyString(responseId) ||
|
|
1539
|
+
!isSha256(assistantContentSha256) ||
|
|
1540
|
+
!isSha256(conversationStaticSha256) ||
|
|
1541
|
+
typeof requestMessageCount !== 'number' ||
|
|
1542
|
+
!Number.isSafeInteger(requestMessageCount) ||
|
|
1543
|
+
requestMessageCount < 0 ||
|
|
1544
|
+
!isSha256(requestMessagesSha256) ||
|
|
1545
|
+
!isSha256(cacheProfileSha256) ||
|
|
1546
|
+
(cacheRetention !== 'none' && cacheRetention !== 'short' && cacheRetention !== 'long') ||
|
|
1547
|
+
(compactionBoundarySha256 !== null && !isSha256(compactionBoundarySha256)) ||
|
|
1548
|
+
!isSha256(signatureEpochSha256) ||
|
|
1549
|
+
typeof signatureEpochInheritsPrior !== 'boolean' ||
|
|
1550
|
+
(previousMessageId !== null && !isNonEmptyString(previousMessageId))
|
|
1490
1551
|
) {
|
|
1491
1552
|
return undefined;
|
|
1492
1553
|
}
|
|
1493
|
-
|
|
1554
|
+
|
|
1555
|
+
return {
|
|
1556
|
+
schema_version: ANTHROPIC_LINEAGE_SCHEMA,
|
|
1557
|
+
projection_version: ANTHROPIC_PROJECTION_VERSION,
|
|
1558
|
+
source_provider: 'anthropic',
|
|
1559
|
+
source_api: 'anthropic-messages',
|
|
1560
|
+
source_model: sourceModel,
|
|
1561
|
+
response_id: responseId,
|
|
1562
|
+
assistant_content_sha256: assistantContentSha256,
|
|
1563
|
+
conversation_static_sha256: conversationStaticSha256,
|
|
1564
|
+
request_message_count: requestMessageCount,
|
|
1565
|
+
request_messages_sha256: requestMessagesSha256,
|
|
1566
|
+
cache_profile_sha256: cacheProfileSha256,
|
|
1567
|
+
cache_retention: cacheRetention,
|
|
1568
|
+
compaction_boundary_sha256: compactionBoundarySha256,
|
|
1569
|
+
signature_epoch_sha256: signatureEpochSha256,
|
|
1570
|
+
signature_epoch_inherits_prior: signatureEpochInheritsPrior,
|
|
1571
|
+
previous_message_id: previousMessageId,
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
function isSuccessfulLineageStopReason(
|
|
1576
|
+
stopReason: string | undefined,
|
|
1577
|
+
): stopReason is 'stop' | 'length' | 'toolUse' {
|
|
1578
|
+
return stopReason === 'stop' || stopReason === 'length' || stopReason === 'toolUse';
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
function lineageBindsContainingAssistant(
|
|
1582
|
+
message: Extract<PiMessage, { role: 'assistant' }>,
|
|
1583
|
+
lineage: AnthropicLineageDetails,
|
|
1584
|
+
): boolean {
|
|
1585
|
+
return (
|
|
1586
|
+
message.provider === lineage.source_provider &&
|
|
1587
|
+
message.api === lineage.source_api &&
|
|
1588
|
+
isNonEmptyString(message.model) &&
|
|
1589
|
+
message.model === lineage.source_model &&
|
|
1590
|
+
isSuccessfulLineageStopReason(message.stopReason) &&
|
|
1591
|
+
isNonEmptyString(message.responseId) &&
|
|
1592
|
+
message.responseId === lineage.response_id &&
|
|
1593
|
+
lineage.assistant_content_sha256 === assistantContentHash(message.content)
|
|
1594
|
+
);
|
|
1494
1595
|
}
|
|
1495
1596
|
|
|
1496
1597
|
function canTargetReadAnthropicThinking(sourceModel: string, targetModel: string): boolean {
|
|
@@ -1529,11 +1630,25 @@ function resolveSignatureEpochPolicy(
|
|
|
1529
1630
|
compactionBoundarySha256: string | null,
|
|
1530
1631
|
): SignatureEpochPolicy {
|
|
1531
1632
|
const targetModelId = normalizedAnthropicModelId(model);
|
|
1532
|
-
const
|
|
1533
|
-
if (
|
|
1633
|
+
const latestState = targetLineageState({ messages }, targetModelId);
|
|
1634
|
+
if (latestState.kind === 'none') {
|
|
1534
1635
|
return initialSignatureEpochPolicy(targetModelId, cacheRetention, compactionBoundarySha256);
|
|
1535
1636
|
}
|
|
1637
|
+
if (latestState.kind === 'untrusted') {
|
|
1638
|
+
return {
|
|
1639
|
+
sha256: sha256Canonical({
|
|
1640
|
+
projection_version: ANTHROPIC_PROJECTION_VERSION,
|
|
1641
|
+
kind: 'untrusted-lineage-reset',
|
|
1642
|
+
target_model: targetModelId,
|
|
1643
|
+
cache_retention: cacheRetention,
|
|
1644
|
+
compaction_boundary_sha256: compactionBoundarySha256,
|
|
1645
|
+
latest_assistant_sha256: latestState.assistantSha256,
|
|
1646
|
+
}),
|
|
1647
|
+
inheritsPrior: false,
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1536
1650
|
|
|
1651
|
+
const latest = latestState.lineage;
|
|
1537
1652
|
const retentionChanged = latest.cache_retention !== cacheRetention;
|
|
1538
1653
|
const declaredNewCompaction =
|
|
1539
1654
|
compactionBoundarySha256 !== null &&
|
|
@@ -1565,22 +1680,12 @@ function isTrustedReplayableAnthropicAssistant(
|
|
|
1565
1680
|
conversationStaticSha256: string,
|
|
1566
1681
|
wireMessagesBeforeAssistant: readonly JsonObject[],
|
|
1567
1682
|
): boolean {
|
|
1568
|
-
if (
|
|
1569
|
-
message.provider !== 'anthropic' ||
|
|
1570
|
-
message.api !== 'anthropic-messages' ||
|
|
1571
|
-
typeof message.model !== 'string' ||
|
|
1572
|
-
message.stopReason === 'error' ||
|
|
1573
|
-
message.stopReason === 'aborted' ||
|
|
1574
|
-
!canTargetReadAnthropicThinking(message.model, normalizedAnthropicModelId(targetModel))
|
|
1575
|
-
) {
|
|
1576
|
-
return false;
|
|
1577
|
-
}
|
|
1683
|
+
if (typeof message.model !== 'string') return false;
|
|
1578
1684
|
const lineage = parseAnthropicLineageDetails(message);
|
|
1579
1685
|
if (
|
|
1580
1686
|
lineage === undefined ||
|
|
1581
|
-
lineage
|
|
1582
|
-
|
|
1583
|
-
lineage.assistant_content_sha256 !== assistantContentHash(message.content) ||
|
|
1687
|
+
!lineageBindsContainingAssistant(message, lineage) ||
|
|
1688
|
+
!canTargetReadAnthropicThinking(message.model, normalizedAnthropicModelId(targetModel)) ||
|
|
1584
1689
|
lineage.cache_retention !== targetCacheRetention ||
|
|
1585
1690
|
lineage.conversation_static_sha256 !== conversationStaticSha256 ||
|
|
1586
1691
|
lineage.request_message_count !== wireMessagesBeforeAssistant.length ||
|
|
@@ -1858,12 +1963,20 @@ export function buildAnthropicRequestParams(
|
|
|
1858
1963
|
context: PiStreamContext,
|
|
1859
1964
|
options?: PiSimpleStreamOptions,
|
|
1860
1965
|
): JsonObject {
|
|
1966
|
+
return buildAnthropicRequest(model, context, options).params;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
function buildAnthropicRequest(
|
|
1970
|
+
model: PiModelLike,
|
|
1971
|
+
context: PiStreamContext,
|
|
1972
|
+
options?: PiSimpleStreamOptions,
|
|
1973
|
+
): { readonly params: JsonObject; readonly signatureEpoch: SignatureEpochPolicy } {
|
|
1861
1974
|
const policy = resolveClaudeCodeModelPolicy(model);
|
|
1862
1975
|
const maxTokens = resolveAnthropicMaxTokens(model);
|
|
1863
1976
|
const cacheControl = resolveAnthropicCacheControl(model, options);
|
|
1864
1977
|
const cacheRetention: CacheRetention =
|
|
1865
1978
|
cacheControl === undefined ? 'none' : cacheControl.ttl === '1h' ? 'long' : 'short';
|
|
1866
|
-
|
|
1979
|
+
let signatureEpoch = resolveSignatureEpochPolicy(
|
|
1867
1980
|
model,
|
|
1868
1981
|
context.messages,
|
|
1869
1982
|
cacheRetention,
|
|
@@ -1934,8 +2047,37 @@ export function buildAnthropicRequestParams(
|
|
|
1934
2047
|
params['thinking'] = { type: 'disabled' };
|
|
1935
2048
|
params['temperature'] = options?.temperature ?? 1;
|
|
1936
2049
|
}
|
|
2050
|
+
const previous = latestLineageForTarget(context, normalizedAnthropicModelId(model));
|
|
2051
|
+
if (
|
|
2052
|
+
previous !== undefined &&
|
|
2053
|
+
signatureEpoch.sha256 === previous.signature_epoch_sha256 &&
|
|
2054
|
+
(previous.cache_profile_sha256 !== cacheProfileHash(model, policy, params, staticSha256) ||
|
|
2055
|
+
!hasLineageRequestPrefix(requestMessagesFromPayload(params), previous))
|
|
2056
|
+
) {
|
|
2057
|
+
// Resume/reload and profile edits can invalidate a lane. Re-project before transport,
|
|
2058
|
+
// rather than just clearing the response ID while retaining prefix-bound signatures.
|
|
2059
|
+
signatureEpoch = {
|
|
2060
|
+
sha256: sha256Canonical({
|
|
2061
|
+
projection_version: ANTHROPIC_PROJECTION_VERSION,
|
|
2062
|
+
kind: 'lineage-reset',
|
|
2063
|
+
previous_signature_epoch_sha256: previous.signature_epoch_sha256,
|
|
2064
|
+
previous_response_id: previous.response_id,
|
|
2065
|
+
cache_profile_sha256: cacheProfileHash(model, policy, params, staticSha256),
|
|
2066
|
+
request_messages_sha256: promptMessagesHash(requestMessagesFromPayload(params)),
|
|
2067
|
+
}),
|
|
2068
|
+
inheritsPrior: false,
|
|
2069
|
+
};
|
|
2070
|
+
params['messages'] = convertMessages(
|
|
2071
|
+
model,
|
|
2072
|
+
context.messages,
|
|
2073
|
+
staticSha256,
|
|
2074
|
+
cacheRetention,
|
|
2075
|
+
signatureEpoch,
|
|
2076
|
+
cacheControl,
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
1937
2079
|
assertCacheControlBreakpointLimit(params);
|
|
1938
|
-
return params;
|
|
2080
|
+
return { params, signatureEpoch };
|
|
1939
2081
|
}
|
|
1940
2082
|
|
|
1941
2083
|
interface PreparedAnthropicLineage {
|
|
@@ -2001,24 +2143,68 @@ function cacheRetentionFromPayload(payload: JsonObject): CacheRetention {
|
|
|
2001
2143
|
return inspectCacheControls(payload).retention ?? 'none';
|
|
2002
2144
|
}
|
|
2003
2145
|
|
|
2004
|
-
|
|
2146
|
+
type TargetLineageState =
|
|
2147
|
+
| { readonly kind: 'none' }
|
|
2148
|
+
| { readonly kind: 'trusted'; readonly lineage: AnthropicLineageDetails }
|
|
2149
|
+
| { readonly kind: 'untrusted'; readonly assistantSha256: string };
|
|
2150
|
+
|
|
2151
|
+
function untrustedAssistantSha256(
|
|
2152
|
+
message: Extract<PiMessage, { role: 'assistant' }>,
|
|
2153
|
+
): string {
|
|
2154
|
+
return sha256Canonical({
|
|
2155
|
+
provider: message.provider ?? null,
|
|
2156
|
+
api: message.api ?? null,
|
|
2157
|
+
model: message.model ?? null,
|
|
2158
|
+
response_id: message.responseId ?? null,
|
|
2159
|
+
stop_reason: message.stopReason ?? null,
|
|
2160
|
+
assistant_content_sha256: assistantContentHash(message.content),
|
|
2161
|
+
lineage_diagnostics: (message.diagnostics ?? []).filter(
|
|
2162
|
+
(diagnostic) => diagnostic.type === ANTHROPIC_LINEAGE_DIAGNOSTIC_TYPE,
|
|
2163
|
+
),
|
|
2164
|
+
});
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
function targetLineageState(
|
|
2005
2168
|
context: PiStreamContext,
|
|
2006
2169
|
targetModelId: string,
|
|
2007
|
-
):
|
|
2170
|
+
): TargetLineageState {
|
|
2008
2171
|
for (let index = context.messages.length - 1; index >= 0; index -= 1) {
|
|
2009
2172
|
const message = context.messages[index];
|
|
2173
|
+
if (message?.role !== 'assistant') continue;
|
|
2174
|
+
|
|
2175
|
+
const lineageDiagnostics = (message.diagnostics ?? []).filter(
|
|
2176
|
+
(diagnostic) => diagnostic.type === ANTHROPIC_LINEAGE_DIAGNOSTIC_TYPE,
|
|
2177
|
+
);
|
|
2178
|
+
const latestRawDetails = lineageDiagnostics.at(-1)?.details;
|
|
2179
|
+
const receiptClaimsTarget = latestRawDetails?.['source_model'] === targetModelId;
|
|
2180
|
+
const assistantClaimsTarget = message.model === targetModelId;
|
|
2181
|
+
if (!assistantClaimsTarget && !receiptClaimsTarget) continue;
|
|
2182
|
+
|
|
2010
2183
|
if (
|
|
2011
|
-
message
|
|
2012
|
-
|
|
2013
|
-
message.stopReason === 'error' ||
|
|
2014
|
-
message.stopReason === 'aborted'
|
|
2184
|
+
(message.stopReason === 'error' || message.stopReason === 'aborted') &&
|
|
2185
|
+
lineageDiagnostics.length === 0
|
|
2015
2186
|
) {
|
|
2016
2187
|
continue;
|
|
2017
2188
|
}
|
|
2189
|
+
|
|
2018
2190
|
const lineage = parseAnthropicLineageDetails(message);
|
|
2019
|
-
|
|
2191
|
+
if (
|
|
2192
|
+
lineage?.source_model === targetModelId &&
|
|
2193
|
+
lineageBindsContainingAssistant(message, lineage)
|
|
2194
|
+
) {
|
|
2195
|
+
return { kind: 'trusted', lineage };
|
|
2196
|
+
}
|
|
2197
|
+
return { kind: 'untrusted', assistantSha256: untrustedAssistantSha256(message) };
|
|
2020
2198
|
}
|
|
2021
|
-
return
|
|
2199
|
+
return { kind: 'none' };
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
function latestLineageForTarget(
|
|
2203
|
+
context: PiStreamContext,
|
|
2204
|
+
targetModelId: string,
|
|
2205
|
+
): AnthropicLineageDetails | undefined {
|
|
2206
|
+
const state = targetLineageState(context, targetModelId);
|
|
2207
|
+
return state.kind === 'trusted' ? state.lineage : undefined;
|
|
2022
2208
|
}
|
|
2023
2209
|
|
|
2024
2210
|
function declaredCompactionBoundarySha256(messages: readonly JsonObject[]): string | null {
|
|
@@ -2035,11 +2221,23 @@ function declaredCompactionBoundarySha256(messages: readonly JsonObject[]): stri
|
|
|
2035
2221
|
return sha256Canonical(promptMessagesWithoutCacheControls([firstMessage])[0]);
|
|
2036
2222
|
}
|
|
2037
2223
|
|
|
2224
|
+
function hasLineageRequestPrefix(
|
|
2225
|
+
messages: readonly JsonObject[],
|
|
2226
|
+
previous: AnthropicLineageDetails,
|
|
2227
|
+
): boolean {
|
|
2228
|
+
return (
|
|
2229
|
+
messages.length >= previous.request_message_count &&
|
|
2230
|
+
promptMessagesHash(messages.slice(0, previous.request_message_count)) ===
|
|
2231
|
+
previous.request_messages_sha256
|
|
2232
|
+
);
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2038
2235
|
function prepareAnthropicLineageDetails(args: {
|
|
2039
2236
|
readonly model: PiModelLike;
|
|
2040
2237
|
readonly policy: ClaudeCodeModelPolicy;
|
|
2041
2238
|
readonly context: PiStreamContext;
|
|
2042
2239
|
readonly payload: JsonObject;
|
|
2240
|
+
readonly signatureEpoch: SignatureEpochPolicy;
|
|
2043
2241
|
}): PreparedAnthropicLineage['details'] {
|
|
2044
2242
|
const targetModelId = normalizedAnthropicModelId(args.model);
|
|
2045
2243
|
const messages = requestMessagesFromPayload(args.payload);
|
|
@@ -2050,37 +2248,16 @@ function prepareAnthropicLineageDetails(args: {
|
|
|
2050
2248
|
const profileSha256 = cacheProfileHash(args.model, args.policy, args.payload, staticSha256);
|
|
2051
2249
|
const cacheRetention = cacheRetentionFromPayload(args.payload);
|
|
2052
2250
|
const compactionBoundarySha256 = declaredCompactionBoundarySha256(messages);
|
|
2053
|
-
const signatureEpoch =
|
|
2054
|
-
args.model,
|
|
2055
|
-
args.context.messages,
|
|
2056
|
-
cacheRetention,
|
|
2057
|
-
compactionBoundarySha256,
|
|
2058
|
-
);
|
|
2251
|
+
const signatureEpoch = args.signatureEpoch;
|
|
2059
2252
|
let previous = latestLineageForTarget(args.context, targetModelId);
|
|
2060
|
-
if (
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
compactionBoundarySha256 !== previous.compaction_boundary_sha256
|
|
2069
|
-
) {
|
|
2070
|
-
previous = undefined;
|
|
2071
|
-
} else {
|
|
2072
|
-
if (!prefixStillExists) {
|
|
2073
|
-
throw new Error(
|
|
2074
|
-
'Anthropic cache lineage diverged before transport: message history is not append-only',
|
|
2075
|
-
);
|
|
2076
|
-
}
|
|
2077
|
-
if (previous.cache_profile_sha256 !== profileSha256) {
|
|
2078
|
-
throw new Error(
|
|
2079
|
-
'Anthropic cache lineage diverged before transport: model/system/tools/thinking/beta profile changed',
|
|
2080
|
-
);
|
|
2081
|
-
}
|
|
2082
|
-
if (previous.cache_retention !== cacheRetention) previous = undefined;
|
|
2083
|
-
}
|
|
2253
|
+
if (
|
|
2254
|
+
previous !== undefined &&
|
|
2255
|
+
(signatureEpoch.sha256 !== previous.signature_epoch_sha256 ||
|
|
2256
|
+
!hasLineageRequestPrefix(messages, previous) ||
|
|
2257
|
+
previous.cache_profile_sha256 !== profileSha256 ||
|
|
2258
|
+
previous.cache_retention !== cacheRetention)
|
|
2259
|
+
) {
|
|
2260
|
+
previous = undefined;
|
|
2084
2261
|
}
|
|
2085
2262
|
return {
|
|
2086
2263
|
schema_version: ANTHROPIC_LINEAGE_SCHEMA,
|
|
@@ -2109,6 +2286,7 @@ class AnthropicLineageCoordinator {
|
|
|
2109
2286
|
readonly policy: ClaudeCodeModelPolicy;
|
|
2110
2287
|
readonly context: PiStreamContext;
|
|
2111
2288
|
readonly payload: JsonObject;
|
|
2289
|
+
readonly signatureEpoch: SignatureEpochPolicy;
|
|
2112
2290
|
}): PreparedAnthropicLineage {
|
|
2113
2291
|
const targetModelId = normalizedAnthropicModelId(args.model);
|
|
2114
2292
|
const key = `${args.sessionId}\u0000${targetModelId}`;
|
|
@@ -2136,6 +2314,14 @@ export function createAnthropicLineageDiagnostic(args: {
|
|
|
2136
2314
|
readonly requestPayload: JsonObject;
|
|
2137
2315
|
readonly previousMessageId?: string | null;
|
|
2138
2316
|
}): PiAssistantDiagnosticLike {
|
|
2317
|
+
if (!isNonEmptyString(args.responseId)) {
|
|
2318
|
+
throw new Error('Anthropic lineage diagnostic requires a non-empty response ID');
|
|
2319
|
+
}
|
|
2320
|
+
if (args.previousMessageId !== undefined && args.previousMessageId !== null) {
|
|
2321
|
+
if (!isNonEmptyString(args.previousMessageId)) {
|
|
2322
|
+
throw new Error('Anthropic lineage diagnostic requires a non-empty previous response ID');
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2139
2325
|
const policy = resolveClaudeCodeModelPolicy(args.model);
|
|
2140
2326
|
const messages = requestMessagesFromPayload(args.requestPayload);
|
|
2141
2327
|
const staticSha256 = conversationStaticHash(
|
|
@@ -2177,7 +2363,7 @@ function appendLineageDiagnostic(
|
|
|
2177
2363
|
output: AssistantMessageLike,
|
|
2178
2364
|
prepared: PreparedAnthropicLineage,
|
|
2179
2365
|
): void {
|
|
2180
|
-
if (
|
|
2366
|
+
if (!isNonEmptyString(output.responseId)) {
|
|
2181
2367
|
throw new Error(
|
|
2182
2368
|
'Anthropic attribution successful response is missing responseId lineage proof',
|
|
2183
2369
|
);
|
|
@@ -2488,33 +2674,26 @@ function createOutput(model: PiModelLike): AssistantMessageLike {
|
|
|
2488
2674
|
};
|
|
2489
2675
|
}
|
|
2490
2676
|
|
|
2491
|
-
|
|
2677
|
+
type HostForwardingModel = PiModelLike & HostModel<'anthropic-messages'>;
|
|
2678
|
+
type HostForwardingContext = PiStreamContext & HostContext;
|
|
2679
|
+
type HostForwardingOptions = PiSimpleStreamOptions & HostSimpleStreamOptions;
|
|
2680
|
+
type HostForwardingStream = AssistantMessageEventStreamLike & HostAssistantMessageEventStream;
|
|
2681
|
+
|
|
2682
|
+
function forwardToBuiltInAnthropic(
|
|
2492
2683
|
model: PiModelLike,
|
|
2493
2684
|
context: PiStreamContext,
|
|
2494
2685
|
options: PiSimpleStreamOptions | undefined,
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
) => AssistantMessageEventStreamLike;
|
|
2507
|
-
}>;
|
|
2508
|
-
const mod = await dynamicImport('@earendil-works/pi-ai/anthropic');
|
|
2509
|
-
const delegated = mod.streamSimpleAnthropic(model, context, options);
|
|
2510
|
-
for await (const event of delegated) stream.push(event);
|
|
2511
|
-
stream.end(await delegated.result());
|
|
2512
|
-
} catch (error) {
|
|
2513
|
-
output.stopReason = 'error';
|
|
2514
|
-
output.errorMessage = `Anthropic attribution could not delegate non-target provider ${JSON.stringify(model.provider)}: ${error instanceof Error ? error.message : String(error)}`;
|
|
2515
|
-
stream.push({ type: 'error', reason: 'error', error: output });
|
|
2516
|
-
stream.end();
|
|
2517
|
-
}
|
|
2686
|
+
): AssistantMessageEventStreamLike {
|
|
2687
|
+
// Pi aliases these SDK imports to its own version while loading extensions.
|
|
2688
|
+
// The host therefore owns both its legacy Context or normalized TranscriptContext
|
|
2689
|
+
// input and the complete stream/event/result shape. These intersections only mark
|
|
2690
|
+
// that host-owned boundary; no request, callback, event, or result is reconstructed.
|
|
2691
|
+
const delegated = anthropicMessagesApi().streamSimple(
|
|
2692
|
+
model as HostForwardingModel,
|
|
2693
|
+
context as HostForwardingContext,
|
|
2694
|
+
options as HostForwardingOptions | undefined,
|
|
2695
|
+
);
|
|
2696
|
+
return delegated as HostForwardingStream;
|
|
2518
2697
|
}
|
|
2519
2698
|
|
|
2520
2699
|
export function streamAnthropicViaBetaMessages(
|
|
@@ -2523,14 +2702,12 @@ export function streamAnthropicViaBetaMessages(
|
|
|
2523
2702
|
options?: PiSimpleStreamOptions,
|
|
2524
2703
|
dependencies: AnthropicTransportDependencies = {},
|
|
2525
2704
|
): AssistantMessageEventStreamLike {
|
|
2526
|
-
const stream = createAssistantMessageEventStream();
|
|
2527
|
-
const output = createOutput(model);
|
|
2528
|
-
|
|
2529
2705
|
if (model.provider !== 'anthropic') {
|
|
2530
|
-
|
|
2531
|
-
return stream;
|
|
2706
|
+
return forwardToBuiltInAnthropic(model, context, options);
|
|
2532
2707
|
}
|
|
2533
2708
|
|
|
2709
|
+
const stream = createAssistantMessageEventStream();
|
|
2710
|
+
const output = createOutput(model);
|
|
2534
2711
|
void (async () => {
|
|
2535
2712
|
let preparedLineage: PreparedAnthropicLineage | undefined;
|
|
2536
2713
|
try {
|
|
@@ -2548,11 +2725,12 @@ export function streamAnthropicViaBetaMessages(
|
|
|
2548
2725
|
|
|
2549
2726
|
const sessionId = requireSessionId(options?.sessionId, 'options.sessionId');
|
|
2550
2727
|
const account = requireAttributionAccount(
|
|
2551
|
-
|
|
2728
|
+
dependencies.loadAccount?.() ?? loadClaudeAttributionAccount(undefined, options?.env),
|
|
2552
2729
|
);
|
|
2553
2730
|
const url = resolveAnthropicBetaMessagesUrl(model);
|
|
2554
2731
|
const policy = resolveClaudeCodeModelPolicy(model);
|
|
2555
|
-
|
|
2732
|
+
const request = buildAnthropicRequest(model, context, options);
|
|
2733
|
+
let params = request.params;
|
|
2556
2734
|
const billingSystemText = buildClaudeCodeBillingSystemText(
|
|
2557
2735
|
firstUserMessageTextFromPayload(params),
|
|
2558
2736
|
);
|
|
@@ -2561,6 +2739,7 @@ export function streamAnthropicViaBetaMessages(
|
|
|
2561
2739
|
policy,
|
|
2562
2740
|
context,
|
|
2563
2741
|
payload: params,
|
|
2742
|
+
signatureEpoch: request.signatureEpoch,
|
|
2564
2743
|
});
|
|
2565
2744
|
if (policy.supportsCacheDiagnostics) {
|
|
2566
2745
|
if (!policy.beta.split(',').includes(ANTHROPIC_CACHE_DIAGNOSTICS_BETA)) {
|
|
@@ -2608,6 +2787,7 @@ export function streamAnthropicViaBetaMessages(
|
|
|
2608
2787
|
policy,
|
|
2609
2788
|
context,
|
|
2610
2789
|
payload: params,
|
|
2790
|
+
signatureEpoch: request.signatureEpoch,
|
|
2611
2791
|
});
|
|
2612
2792
|
if (
|
|
2613
2793
|
preparedLineage.details.previous_message_id !== provisionalLineage.previous_message_id ||
|
|
@@ -2693,7 +2873,7 @@ export function streamAnthropicViaBetaMessages(
|
|
|
2693
2873
|
'Anthropic beta messages stream emitted malformed/duplicate message_start',
|
|
2694
2874
|
);
|
|
2695
2875
|
}
|
|
2696
|
-
if (
|
|
2876
|
+
if (!isNonEmptyString(event['message']['id'])) {
|
|
2697
2877
|
throw new Error('Anthropic beta messages message_start is missing a response id');
|
|
2698
2878
|
}
|
|
2699
2879
|
sawMessageStart = true;
|