@sync.so/mcp-server 0.1.3 → 0.2.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/README.md +261 -86
- package/deploy/generation-status/app.html.gz +0 -0
- package/deploy/generation-status/release.json +6 -0
- package/dist/abort-signals.d.ts +6 -0
- package/dist/abort-signals.d.ts.map +1 -0
- package/dist/abort-signals.js +23 -0
- package/dist/account-features.d.ts +7 -0
- package/dist/account-features.d.ts.map +1 -0
- package/dist/account-features.js +48 -0
- package/dist/app-upload-relay.d.ts +13 -0
- package/dist/app-upload-relay.d.ts.map +1 -0
- package/dist/app-upload-relay.js +136 -0
- package/dist/asset-thumbnail.d.ts +3 -0
- package/dist/asset-thumbnail.d.ts.map +1 -0
- package/dist/asset-thumbnail.js +2 -0
- package/dist/auth/async-context.d.ts +5 -0
- package/dist/auth/async-context.d.ts.map +1 -0
- package/dist/auth/async-context.js +14 -0
- package/dist/auth/bearer-auth.d.ts +16 -0
- package/dist/auth/bearer-auth.d.ts.map +1 -0
- package/dist/auth/bearer-auth.js +55 -0
- package/dist/auth/client-credentials.d.ts +13 -0
- package/dist/auth/client-credentials.d.ts.map +1 -0
- package/dist/auth/client-credentials.js +67 -0
- package/dist/auth/device-auth.d.ts.map +1 -1
- package/dist/auth/device-auth.js +3 -2
- package/dist/auth/fixture-cleanup.d.ts +4 -0
- package/dist/auth/fixture-cleanup.d.ts.map +1 -0
- package/dist/auth/fixture-cleanup.js +9 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +2 -0
- package/dist/auth/oauth-diagnostics.d.ts +11 -0
- package/dist/auth/oauth-diagnostics.d.ts.map +1 -0
- package/dist/auth/oauth-diagnostics.js +78 -0
- package/dist/auth/oauth-provider.d.ts +16 -0
- package/dist/auth/oauth-provider.d.ts.map +1 -0
- package/dist/auth/oauth-provider.js +107 -0
- package/dist/auth/resource-metadata.d.ts +2 -0
- package/dist/auth/resource-metadata.d.ts.map +1 -0
- package/dist/auth/resource-metadata.js +3 -0
- package/dist/auth/token-verification.d.ts +11 -0
- package/dist/auth/token-verification.d.ts.map +1 -0
- package/dist/auth/token-verification.js +99 -0
- package/dist/auth/verification-cache.d.ts +8 -0
- package/dist/auth/verification-cache.d.ts.map +1 -0
- package/dist/auth/verification-cache.js +111 -0
- package/dist/chatgpt-analytics.d.ts +22 -0
- package/dist/chatgpt-analytics.d.ts.map +1 -0
- package/dist/chatgpt-analytics.js +172 -0
- package/dist/chatgpt-app.d.ts +15 -0
- package/dist/chatgpt-app.d.ts.map +1 -0
- package/dist/chatgpt-app.js +133 -0
- package/dist/chatgpt-release.d.ts +12 -0
- package/dist/chatgpt-release.d.ts.map +1 -0
- package/dist/chatgpt-release.js +30 -0
- package/dist/cli.js +30 -16
- package/dist/client-profile.d.ts +10 -0
- package/dist/client-profile.d.ts.map +1 -0
- package/dist/client-profile.js +45 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +52 -0
- package/dist/generation-status-html.d.ts +2 -0
- package/dist/generation-status-html.d.ts.map +1 -0
- package/dist/generation-status-html.js +26 -0
- package/dist/generation-status.d.ts +6 -0
- package/dist/generation-status.d.ts.map +1 -0
- package/dist/generation-status.js +37 -0
- package/dist/http-client.d.ts +45 -1
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +171 -34
- package/dist/http-server.d.ts +53 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +753 -0
- package/dist/http-session.d.ts +18 -0
- package/dist/http-session.d.ts.map +1 -0
- package/dist/http-session.js +189 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/oauth-response.d.ts +3 -0
- package/dist/oauth-response.d.ts.map +1 -0
- package/dist/oauth-response.js +30 -0
- package/dist/openapi/index.d.ts +2 -2
- package/dist/openapi/index.d.ts.map +1 -1
- package/dist/openapi/index.js +1 -1
- package/dist/openapi/parser.d.ts +2 -0
- package/dist/openapi/parser.d.ts.map +1 -1
- package/dist/openapi/parser.js +41 -1
- package/dist/openapi/types.d.ts +3 -0
- package/dist/openapi/types.d.ts.map +1 -1
- package/dist/organization-selection.d.ts +61 -0
- package/dist/organization-selection.d.ts.map +1 -0
- package/dist/organization-selection.js +142 -0
- package/dist/rate-limits.d.ts +13 -0
- package/dist/rate-limits.d.ts.map +1 -0
- package/dist/rate-limits.js +67 -0
- package/dist/revision.d.ts +6 -0
- package/dist/revision.d.ts.map +1 -0
- package/dist/revision.js +17 -0
- package/dist/runtime-diagnostics.d.ts +32 -0
- package/dist/runtime-diagnostics.d.ts.map +1 -0
- package/dist/runtime-diagnostics.js +58 -0
- package/dist/server.d.ts +23 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +893 -32
- package/dist/session-registry.d.ts +54 -0
- package/dist/session-registry.d.ts.map +1 -0
- package/dist/session-registry.js +202 -0
- package/dist/session-telemetry.d.ts +13 -0
- package/dist/session-telemetry.d.ts.map +1 -0
- package/dist/session-telemetry.js +87 -0
- package/dist/spend-confirmation.d.ts +21 -0
- package/dist/spend-confirmation.d.ts.map +1 -0
- package/dist/spend-confirmation.js +105 -0
- package/dist/tool-analytics-context.d.ts +11 -0
- package/dist/tool-analytics-context.d.ts.map +1 -0
- package/dist/tool-analytics-context.js +8 -0
- package/dist/tool-names.d.ts +35 -0
- package/dist/tool-names.d.ts.map +1 -0
- package/dist/tool-names.js +133 -0
- package/dist/tools/account-context.d.ts +5 -0
- package/dist/tools/account-context.d.ts.map +1 -0
- package/dist/tools/account-context.js +131 -0
- package/dist/tools/account-management.d.ts +4 -0
- package/dist/tools/account-management.d.ts.map +1 -0
- package/dist/tools/account-management.js +111 -0
- package/dist/tools/app-tools.d.ts +31 -0
- package/dist/tools/app-tools.d.ts.map +1 -0
- package/dist/tools/app-tools.js +350 -0
- package/dist/tools/asset-analysis.d.ts +4 -0
- package/dist/tools/asset-analysis.d.ts.map +1 -0
- package/dist/tools/asset-analysis.js +172 -0
- package/dist/tools/asset-creators.d.ts +4 -0
- package/dist/tools/asset-creators.d.ts.map +1 -0
- package/dist/tools/asset-creators.js +38 -0
- package/dist/tools/audio-trim.d.ts +6 -0
- package/dist/tools/audio-trim.d.ts.map +1 -0
- package/dist/tools/audio-trim.js +79 -0
- package/dist/tools/batch-results.d.ts +16 -0
- package/dist/tools/batch-results.d.ts.map +1 -0
- package/dist/tools/batch-results.js +103 -0
- package/dist/tools/batches.d.ts +28 -0
- package/dist/tools/batches.d.ts.map +1 -0
- package/dist/tools/batches.js +293 -0
- package/dist/tools/dialogue.d.ts +6 -0
- package/dist/tools/dialogue.d.ts.map +1 -0
- package/dist/tools/dialogue.js +309 -0
- package/dist/tools/estimate-duration.d.ts +35 -0
- package/dist/tools/estimate-duration.d.ts.map +1 -0
- package/dist/tools/estimate-duration.js +66 -0
- package/dist/tools/feedback.d.ts +14 -0
- package/dist/tools/feedback.d.ts.map +1 -0
- package/dist/tools/feedback.js +72 -0
- package/dist/tools/generated-adapters.d.ts +25 -0
- package/dist/tools/generated-adapters.d.ts.map +1 -0
- package/dist/tools/generated-adapters.js +143 -0
- package/dist/tools/generation-context.d.ts +14 -0
- package/dist/tools/generation-context.d.ts.map +1 -0
- package/dist/tools/generation-context.js +39 -0
- package/dist/tools/generation-continuation.d.ts +4 -0
- package/dist/tools/generation-continuation.d.ts.map +1 -0
- package/dist/tools/generation-continuation.js +124 -0
- package/dist/tools/generation-costs.d.ts +6 -0
- package/dist/tools/generation-costs.d.ts.map +1 -0
- package/dist/tools/generation-costs.js +67 -0
- package/dist/tools/generation-output.d.ts +3 -0
- package/dist/tools/generation-output.d.ts.map +1 -0
- package/dist/tools/generation-output.js +39 -0
- package/dist/tools/generator.d.ts +35 -2
- package/dist/tools/generator.d.ts.map +1 -1
- package/dist/tools/generator.js +127 -9
- package/dist/tools/job-status.d.ts +35 -0
- package/dist/tools/job-status.d.ts.map +1 -0
- package/dist/tools/job-status.js +92 -0
- package/dist/tools/job-wait.d.ts +41 -0
- package/dist/tools/job-wait.d.ts.map +1 -0
- package/dist/tools/job-wait.js +84 -0
- package/dist/tools/jobs.d.ts +3 -0
- package/dist/tools/jobs.d.ts.map +1 -0
- package/dist/tools/jobs.js +210 -0
- package/dist/tools/media-upload.d.ts +27 -0
- package/dist/tools/media-upload.d.ts.map +1 -0
- package/dist/tools/media-upload.js +247 -0
- package/dist/tools/model-options.d.ts +36 -0
- package/dist/tools/model-options.d.ts.map +1 -0
- package/dist/tools/model-options.js +48 -0
- package/dist/tools/organization-choice.d.ts +9 -0
- package/dist/tools/organization-choice.d.ts.map +1 -0
- package/dist/tools/organization-choice.js +136 -0
- package/dist/tools/organizations.d.ts +56 -0
- package/dist/tools/organizations.d.ts.map +1 -0
- package/dist/tools/organizations.js +235 -0
- package/dist/tools/output-schemas.d.ts +54 -0
- package/dist/tools/output-schemas.d.ts.map +1 -0
- package/dist/tools/output-schemas.js +58 -0
- package/dist/tools/overrides.d.ts +3 -0
- package/dist/tools/overrides.d.ts.map +1 -1
- package/dist/tools/overrides.js +113 -15
- package/dist/tools/playback-metadata.d.ts +4 -0
- package/dist/tools/playback-metadata.d.ts.map +1 -0
- package/dist/tools/playback-metadata.js +51 -0
- package/dist/tools/project-destination.d.ts +13 -0
- package/dist/tools/project-destination.d.ts.map +1 -0
- package/dist/tools/project-destination.js +45 -0
- package/dist/tools/project-history.d.ts +6 -0
- package/dist/tools/project-history.d.ts.map +1 -0
- package/dist/tools/project-history.js +45 -0
- package/dist/tools/project-intent.d.ts +8 -0
- package/dist/tools/project-intent.d.ts.map +1 -0
- package/dist/tools/project-intent.js +87 -0
- package/dist/tools/running-submissions.d.ts +7 -0
- package/dist/tools/running-submissions.d.ts.map +1 -0
- package/dist/tools/running-submissions.js +91 -0
- package/dist/tools/speech.d.ts +6 -0
- package/dist/tools/speech.d.ts.map +1 -0
- package/dist/tools/speech.js +116 -0
- package/dist/tools/studio-draft.d.ts +7 -0
- package/dist/tools/studio-draft.d.ts.map +1 -0
- package/dist/tools/studio-draft.js +195 -0
- package/dist/tools/studio-view-contract.d.ts +184 -0
- package/dist/tools/studio-view-contract.d.ts.map +1 -0
- package/dist/tools/studio-view-contract.js +67 -0
- package/dist/tools/studio-view.d.ts +6 -0
- package/dist/tools/studio-view.d.ts.map +1 -0
- package/dist/tools/studio-view.js +126 -0
- package/dist/tools/timeline-lipsync.d.ts +316 -0
- package/dist/tools/timeline-lipsync.d.ts.map +1 -0
- package/dist/tools/timeline-lipsync.js +304 -0
- package/dist/tools/translation-preview.d.ts +8 -0
- package/dist/tools/translation-preview.d.ts.map +1 -0
- package/dist/tools/translation-preview.js +146 -0
- package/dist/tools/translation.d.ts +6 -0
- package/dist/tools/translation.d.ts.map +1 -0
- package/dist/tools/translation.js +131 -0
- package/dist/tools/upload-widget.d.ts +13 -0
- package/dist/tools/upload-widget.d.ts.map +1 -0
- package/dist/tools/upload-widget.js +788 -0
- package/dist/toolsets.d.ts +18 -0
- package/dist/toolsets.d.ts.map +1 -0
- package/dist/toolsets.js +157 -0
- package/dist/update-check.d.ts +38 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +150 -0
- package/dist/upload-runtime.d.ts +45 -0
- package/dist/upload-runtime.d.ts.map +1 -0
- package/dist/upload-runtime.js +156 -0
- package/dist/upload-source.d.ts +4 -0
- package/dist/upload-source.d.ts.map +1 -0
- package/dist/upload-source.js +46 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/package.json +79 -33
- package/dist/openapi/parser.test.d.ts +0 -2
- package/dist/openapi/parser.test.d.ts.map +0 -1
- package/dist/openapi/parser.test.js +0 -188
- package/dist/tools/generator.test.d.ts +0 -2
- package/dist/tools/generator.test.d.ts.map +0 -1
- package/dist/tools/generator.test.js +0 -178
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AuthInfo } from '@modelcontextprotocol/server';
|
|
2
|
+
export type SessionOwner = Readonly<{
|
|
3
|
+
sub: string;
|
|
4
|
+
clientId: string;
|
|
5
|
+
organizationId: string | null;
|
|
6
|
+
}>;
|
|
7
|
+
export declare function sessionOwner(auth: AuthInfo | undefined): SessionOwner | undefined;
|
|
8
|
+
type ClosableTransport = {
|
|
9
|
+
close: () => Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
type SessionRemovalReason = 'closed' | 'expired' | 'evicted' | 'shutdown' | 'initialization_failed';
|
|
12
|
+
type SessionRegistryOptions = {
|
|
13
|
+
idleTtlMs: number;
|
|
14
|
+
maxSessions: number;
|
|
15
|
+
canAdmit?: () => boolean;
|
|
16
|
+
now?: () => number;
|
|
17
|
+
onCloseError?: (error: unknown) => void;
|
|
18
|
+
onRemove?: (sessionId: string, reason: SessionRemovalReason) => void;
|
|
19
|
+
};
|
|
20
|
+
type SessionLease<T extends ClosableTransport> = {
|
|
21
|
+
transport: T;
|
|
22
|
+
release: () => void;
|
|
23
|
+
};
|
|
24
|
+
type SessionStats = {
|
|
25
|
+
active: number;
|
|
26
|
+
pending: number;
|
|
27
|
+
inFlight: number;
|
|
28
|
+
created: number;
|
|
29
|
+
expired: number;
|
|
30
|
+
closed: number;
|
|
31
|
+
rejected: number;
|
|
32
|
+
rejectedCapacity: number;
|
|
33
|
+
rejectedMemory: number;
|
|
34
|
+
evicted: number;
|
|
35
|
+
limit: number;
|
|
36
|
+
};
|
|
37
|
+
export declare class SessionRegistry<T extends ClosableTransport> {
|
|
38
|
+
#private;
|
|
39
|
+
constructor(options: SessionRegistryOptions);
|
|
40
|
+
get size(): number;
|
|
41
|
+
stopAccepting(): void;
|
|
42
|
+
reserve(): {
|
|
43
|
+
commit: (sessionId: string, transport: T, owner: SessionOwner) => SessionLease<T>;
|
|
44
|
+
release: () => void;
|
|
45
|
+
} | undefined;
|
|
46
|
+
acquire(sessionId: string, owner: SessionOwner): SessionLease<T> | undefined;
|
|
47
|
+
remove(sessionId: string, reason: SessionRemovalReason, closeTransport?: boolean): Promise<boolean>;
|
|
48
|
+
sweep(): Promise<number>;
|
|
49
|
+
closeAll(): Promise<void>;
|
|
50
|
+
recordRejection(reason: 'capacity' | 'memory'): void;
|
|
51
|
+
stats(): SessionStats;
|
|
52
|
+
}
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=session-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-registry.d.ts","sourceRoot":"","sources":["../src/session-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC,CAAC;AAGH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAajF;AAED,KAAK,iBAAiB,GAAG;IACvB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AASF,KAAK,oBAAoB,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,uBAAuB,CAAC;AAEpG,KAAK,sBAAsB,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;CACtE,CAAC;AAEF,KAAK,YAAY,CAAC,CAAC,SAAS,iBAAiB,IAAI;IAC/C,SAAS,EAAE,CAAC,CAAC;IACb,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,qBAAa,eAAe,CAAC,CAAC,SAAS,iBAAiB;;IAkBtD,YAAY,OAAO,EAAE,sBAAsB,EAO1C;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,aAAa,IAAI,IAAI,CAEpB;IAED,OAAO,IACH;QACE,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC;QAClF,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,GACD,SAAS,CAwDZ;IAED,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAe3E;IAkBK,MAAM,CACV,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,oBAAoB,EAC5B,cAAc,UAAO,GACpB,OAAO,CAAC,OAAO,CAAC,CAsBlB;IAUK,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAQ7B;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAI9B;IAED,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAInD;IAED,KAAK,IAAI,YAAY,CAcpB;CACF"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// Only verified userinfo claims participate; token rotation does not change ownership.
|
|
2
|
+
export function sessionOwner(auth) {
|
|
3
|
+
const sub = auth?.extra?.sub;
|
|
4
|
+
const clientId = auth?.clientId;
|
|
5
|
+
const organizationId = auth?.extra?.organizationId;
|
|
6
|
+
const nonempty = (value) => typeof value === 'string' && value.trim().length > 0;
|
|
7
|
+
if (!nonempty(sub) ||
|
|
8
|
+
!nonempty(clientId) ||
|
|
9
|
+
(organizationId !== undefined && !nonempty(organizationId)))
|
|
10
|
+
return undefined;
|
|
11
|
+
return { sub, clientId, organizationId: organizationId ?? null };
|
|
12
|
+
}
|
|
13
|
+
export class SessionRegistry {
|
|
14
|
+
#entries = new Map();
|
|
15
|
+
#idleTtlMs;
|
|
16
|
+
#maxSessions;
|
|
17
|
+
#canAdmit;
|
|
18
|
+
#now;
|
|
19
|
+
#onCloseError;
|
|
20
|
+
#onRemove;
|
|
21
|
+
#pending = 0;
|
|
22
|
+
#accepting = true;
|
|
23
|
+
#created = 0;
|
|
24
|
+
#expired = 0;
|
|
25
|
+
#closed = 0;
|
|
26
|
+
#rejected = 0;
|
|
27
|
+
#rejectedCapacity = 0;
|
|
28
|
+
#rejectedMemory = 0;
|
|
29
|
+
#evicted = 0;
|
|
30
|
+
constructor(options) {
|
|
31
|
+
this.#idleTtlMs = options.idleTtlMs;
|
|
32
|
+
this.#maxSessions = options.maxSessions;
|
|
33
|
+
this.#canAdmit = options.canAdmit ?? (() => true);
|
|
34
|
+
this.#now = options.now ?? Date.now;
|
|
35
|
+
this.#onCloseError = options.onCloseError ?? (() => undefined);
|
|
36
|
+
this.#onRemove = options.onRemove ?? (() => undefined);
|
|
37
|
+
}
|
|
38
|
+
get size() {
|
|
39
|
+
return this.#entries.size;
|
|
40
|
+
}
|
|
41
|
+
stopAccepting() {
|
|
42
|
+
this.#accepting = false;
|
|
43
|
+
}
|
|
44
|
+
reserve() {
|
|
45
|
+
if (!this.#accepting)
|
|
46
|
+
return undefined;
|
|
47
|
+
// Remove expired entries before admission, even between scheduled sweeps.
|
|
48
|
+
// remove() deletes synchronously; transport shutdown completes independently.
|
|
49
|
+
const now = this.#now();
|
|
50
|
+
for (const [id, entry] of this.#entries) {
|
|
51
|
+
if (entry.inFlight === 0 && now - entry.lastSeenAt > this.#idleTtlMs)
|
|
52
|
+
void this.remove(id, 'expired');
|
|
53
|
+
}
|
|
54
|
+
if (this.#entries.size + this.#pending >= this.#maxSessions) {
|
|
55
|
+
let oldest;
|
|
56
|
+
for (const candidate of this.#entries) {
|
|
57
|
+
const entry = candidate[1];
|
|
58
|
+
// Leave time for initialize/initialized/tool handshakes and brief pauses.
|
|
59
|
+
if (entry.inFlight > 0 || now - entry.lastSeenAt < 30_000)
|
|
60
|
+
continue;
|
|
61
|
+
if (!oldest || entry.lastSeenAt < oldest[1].lastSeenAt)
|
|
62
|
+
oldest = candidate;
|
|
63
|
+
}
|
|
64
|
+
if (oldest)
|
|
65
|
+
void this.remove(oldest[0], 'evicted');
|
|
66
|
+
}
|
|
67
|
+
if (this.#entries.size + this.#pending >= this.#maxSessions) {
|
|
68
|
+
this.recordRejection('capacity');
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
if (!this.#canAdmit()) {
|
|
72
|
+
this.recordRejection('memory');
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
this.#pending += 1;
|
|
76
|
+
let active = true;
|
|
77
|
+
const release = () => {
|
|
78
|
+
if (!active)
|
|
79
|
+
return;
|
|
80
|
+
active = false;
|
|
81
|
+
this.#pending -= 1;
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
commit: (sessionId, transport, owner) => {
|
|
85
|
+
if (!active)
|
|
86
|
+
throw new Error('Session reservation has already been released');
|
|
87
|
+
if (!this.#accepting) {
|
|
88
|
+
release();
|
|
89
|
+
throw new Error('Session registry is shutting down');
|
|
90
|
+
}
|
|
91
|
+
release();
|
|
92
|
+
const entry = {
|
|
93
|
+
transport,
|
|
94
|
+
owner: { ...owner },
|
|
95
|
+
lastSeenAt: this.#now(),
|
|
96
|
+
inFlight: 0,
|
|
97
|
+
};
|
|
98
|
+
this.#entries.set(sessionId, entry);
|
|
99
|
+
this.#created += 1;
|
|
100
|
+
return this.#createLease(entry);
|
|
101
|
+
},
|
|
102
|
+
release,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
acquire(sessionId, owner) {
|
|
106
|
+
const entry = this.#entries.get(sessionId);
|
|
107
|
+
// Deny before touching activity or handing the transport to HTTP dispatch.
|
|
108
|
+
if (!entry ||
|
|
109
|
+
entry.owner.sub !== owner.sub ||
|
|
110
|
+
entry.owner.clientId !== owner.clientId ||
|
|
111
|
+
entry.owner.organizationId !== owner.organizationId)
|
|
112
|
+
return undefined;
|
|
113
|
+
if (entry.inFlight === 0 && this.#now() - entry.lastSeenAt > this.#idleTtlMs) {
|
|
114
|
+
void this.remove(sessionId, 'expired');
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
return this.#createLease(entry);
|
|
118
|
+
}
|
|
119
|
+
#createLease(entry) {
|
|
120
|
+
entry.inFlight += 1;
|
|
121
|
+
entry.lastSeenAt = this.#now();
|
|
122
|
+
let active = true;
|
|
123
|
+
return {
|
|
124
|
+
transport: entry.transport,
|
|
125
|
+
release: () => {
|
|
126
|
+
if (!active)
|
|
127
|
+
return;
|
|
128
|
+
active = false;
|
|
129
|
+
entry.inFlight -= 1;
|
|
130
|
+
entry.lastSeenAt = this.#now();
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
async remove(sessionId, reason, closeTransport = true) {
|
|
135
|
+
const entry = this.#entries.get(sessionId);
|
|
136
|
+
if (!entry)
|
|
137
|
+
return false;
|
|
138
|
+
this.#entries.delete(sessionId);
|
|
139
|
+
if (reason === 'expired')
|
|
140
|
+
this.#expired += 1;
|
|
141
|
+
if (reason === 'closed')
|
|
142
|
+
this.#closed += 1;
|
|
143
|
+
if (reason === 'evicted')
|
|
144
|
+
this.#evicted += 1;
|
|
145
|
+
try {
|
|
146
|
+
this.#onRemove(sessionId, reason);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
this.#reportError(error);
|
|
150
|
+
}
|
|
151
|
+
if (closeTransport) {
|
|
152
|
+
try {
|
|
153
|
+
await entry.transport.close();
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
this.#reportError(error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
#reportError(error) {
|
|
162
|
+
try {
|
|
163
|
+
this.#onCloseError(error);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// Observer failures must never interrupt session cleanup.
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async sweep() {
|
|
170
|
+
const now = this.#now();
|
|
171
|
+
const expiredIds = [...this.#entries.entries()]
|
|
172
|
+
.filter(([, entry]) => entry.inFlight === 0 && now - entry.lastSeenAt > this.#idleTtlMs)
|
|
173
|
+
.map(([sessionId]) => sessionId);
|
|
174
|
+
await Promise.all(expiredIds.map((sessionId) => this.remove(sessionId, 'expired')));
|
|
175
|
+
return expiredIds.length;
|
|
176
|
+
}
|
|
177
|
+
async closeAll() {
|
|
178
|
+
await Promise.all([...this.#entries.keys()].map((sessionId) => this.remove(sessionId, 'shutdown')));
|
|
179
|
+
}
|
|
180
|
+
recordRejection(reason) {
|
|
181
|
+
this.#rejected += 1;
|
|
182
|
+
if (reason === 'capacity')
|
|
183
|
+
this.#rejectedCapacity += 1;
|
|
184
|
+
else
|
|
185
|
+
this.#rejectedMemory += 1;
|
|
186
|
+
}
|
|
187
|
+
stats() {
|
|
188
|
+
return {
|
|
189
|
+
active: this.#entries.size,
|
|
190
|
+
pending: this.#pending,
|
|
191
|
+
inFlight: [...this.#entries.values()].reduce((sum, entry) => sum + entry.inFlight, 0),
|
|
192
|
+
created: this.#created,
|
|
193
|
+
expired: this.#expired,
|
|
194
|
+
closed: this.#closed,
|
|
195
|
+
rejected: this.#rejected,
|
|
196
|
+
rejectedCapacity: this.#rejectedCapacity,
|
|
197
|
+
rejectedMemory: this.#rejectedMemory,
|
|
198
|
+
evicted: this.#evicted,
|
|
199
|
+
limit: this.#maxSessions,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Process-local pseudonyms: never emit bearer/session IDs, user IDs or arguments. */
|
|
2
|
+
export declare class SessionTelemetry {
|
|
3
|
+
#private;
|
|
4
|
+
private readonly emit;
|
|
5
|
+
private readonly now;
|
|
6
|
+
constructor(emit: (event: string, data: Record<string, unknown>) => void, now?: () => number);
|
|
7
|
+
reference(id: string): string;
|
|
8
|
+
start(id: string, name: string | undefined, protocol: unknown): void;
|
|
9
|
+
request(id: string, method: string | readonly string[] | undefined): Record<string, unknown>;
|
|
10
|
+
protocol(id: string, version: string): void;
|
|
11
|
+
close(id: string, reason: string): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=session-telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-telemetry.d.ts","sourceRoot":"","sources":["../src/session-telemetry.ts"],"names":[],"mappings":"AAkBA,sFAAsF;AACtF,qBAAa,gBAAgB;;IAgBzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAFtB,YACmB,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,EAC5D,GAAG,eAAW,EAC7B;IACJ,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5B;IACD,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAanE;IACD,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiB3F;IACD,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAG1C;IACD,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAgBtC;CACF"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createHmac, randomBytes } from 'node:crypto';
|
|
2
|
+
import { resolveClientProfile } from './client-profile.js';
|
|
3
|
+
const CLIENTS = new Set([
|
|
4
|
+
'chatgpt',
|
|
5
|
+
'openai',
|
|
6
|
+
'openai-chatgpt',
|
|
7
|
+
'openai-mcp',
|
|
8
|
+
'openai-mcp (codex)',
|
|
9
|
+
'claude',
|
|
10
|
+
'claude-ai',
|
|
11
|
+
'claude-code',
|
|
12
|
+
'anthropic/claudeai',
|
|
13
|
+
'hermes-agent',
|
|
14
|
+
'mcp',
|
|
15
|
+
]);
|
|
16
|
+
const PROTOCOL = /^\d{4}-\d{2}-\d{2}$/;
|
|
17
|
+
/** Process-local pseudonyms: never emit bearer/session IDs, user IDs or arguments. */
|
|
18
|
+
export class SessionTelemetry {
|
|
19
|
+
emit;
|
|
20
|
+
now;
|
|
21
|
+
#key = randomBytes(32);
|
|
22
|
+
#entries = new Map();
|
|
23
|
+
constructor(emit, now = Date.now) {
|
|
24
|
+
this.emit = emit;
|
|
25
|
+
this.now = now;
|
|
26
|
+
}
|
|
27
|
+
reference(id) {
|
|
28
|
+
return createHmac('sha256', this.#key).update(id).digest('hex').slice(0, 24);
|
|
29
|
+
}
|
|
30
|
+
start(id, name, protocol) {
|
|
31
|
+
const client = name?.toLowerCase();
|
|
32
|
+
this.#entries.set(id, {
|
|
33
|
+
started: this.now(),
|
|
34
|
+
lastRequest: this.now(),
|
|
35
|
+
requests: 0,
|
|
36
|
+
toolCalls: 0,
|
|
37
|
+
discoveries: 0,
|
|
38
|
+
client: client && CLIENTS.has(client) ? client : 'other',
|
|
39
|
+
profile: resolveClientProfile(name).name,
|
|
40
|
+
protocol: typeof protocol === 'string' && PROTOCOL.test(protocol) ? protocol : 'unknown',
|
|
41
|
+
});
|
|
42
|
+
this.request(id, 'initialize');
|
|
43
|
+
}
|
|
44
|
+
request(id, method) {
|
|
45
|
+
const entry = this.#entries.get(id);
|
|
46
|
+
if (!entry)
|
|
47
|
+
return { sessionRef: this.reference(id) };
|
|
48
|
+
entry.requests += 1;
|
|
49
|
+
entry.lastRequest = this.now();
|
|
50
|
+
for (const item of typeof method === 'string' ? [method] : (method ?? [])) {
|
|
51
|
+
if (item === 'tools/call')
|
|
52
|
+
entry.toolCalls += 1;
|
|
53
|
+
if (['tools/list', 'resources/list', 'server/discover'].includes(item))
|
|
54
|
+
entry.discoveries += 1;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
sessionRef: this.reference(id),
|
|
58
|
+
sessionRequest: entry.requests,
|
|
59
|
+
clientName: entry.client,
|
|
60
|
+
clientProfile: entry.profile,
|
|
61
|
+
protocol: entry.protocol,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
protocol(id, version) {
|
|
65
|
+
const entry = this.#entries.get(id);
|
|
66
|
+
if (entry && PROTOCOL.test(version))
|
|
67
|
+
entry.protocol = version;
|
|
68
|
+
}
|
|
69
|
+
close(id, reason) {
|
|
70
|
+
const entry = this.#entries.get(id);
|
|
71
|
+
this.#entries.delete(id);
|
|
72
|
+
if (!entry)
|
|
73
|
+
return;
|
|
74
|
+
this.emit('mcp_session_closed', {
|
|
75
|
+
sessionRef: this.reference(id),
|
|
76
|
+
reason,
|
|
77
|
+
clientName: entry.client,
|
|
78
|
+
clientProfile: entry.profile,
|
|
79
|
+
protocol: entry.protocol,
|
|
80
|
+
requests: entry.requests,
|
|
81
|
+
toolCalls: entry.toolCalls,
|
|
82
|
+
discoveries: entry.discoveries,
|
|
83
|
+
lifetimeMs: this.now() - entry.started,
|
|
84
|
+
idleMs: this.now() - entry.lastRequest,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { McpToolDefinition } from './tools/generator.js';
|
|
2
|
+
/**
|
|
3
|
+
* Unattended mode: an operator who runs the server for automation (a scheduled agent,
|
|
4
|
+
* a pipeline) has already approved spending, so prose telling the agent to quote costs
|
|
5
|
+
* and wait for a human's confirmation only stalls the run. The operator turns it off with
|
|
6
|
+
* SYNC_MCP_SPEND_CONFIRMATION=off or --no-spend-confirmation; agents cannot.
|
|
7
|
+
*
|
|
8
|
+
* Each edit replaces one exact sentence. spend-confirmation.test.ts fails when a sentence
|
|
9
|
+
* below no longer appears in its source, so wording changes cannot silently undo this.
|
|
10
|
+
*/
|
|
11
|
+
type Edit = readonly [from: string, to: string];
|
|
12
|
+
export declare const UNATTENDED_INSTRUCTIONS_PREFIX = "This connection runs unattended automation, and its operator has already approved spending. Do not quote prices, estimate costs or ask anyone to confirm a paid action unless the request is about cost; create once, then poll the returned job. ";
|
|
13
|
+
export declare const DESCRIPTION_EDITS: readonly Edit[];
|
|
14
|
+
export declare const INSTRUCTION_EDITS: readonly Edit[];
|
|
15
|
+
export declare const TOOL_DESCRIPTION_EDITS: Readonly<Record<string, readonly Edit[]>>;
|
|
16
|
+
export declare function applyEdits(text: string, edits: readonly Edit[]): string;
|
|
17
|
+
export declare function withoutSpendConfirmation(tool: McpToolDefinition): McpToolDefinition;
|
|
18
|
+
/** SYNC_MCP_SPEND_CONFIRMATION accepts off/false/0 (unattended) and on/true/1 (default). */
|
|
19
|
+
export declare function parseSpendConfirmation(value: string | undefined): boolean | undefined;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=spend-confirmation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spend-confirmation.d.ts","sourceRoot":"","sources":["../src/spend-confirmation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D;;;;;;;;GAQG;AACH,KAAK,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;AAEhD,eAAO,MAAM,8BAA8B,uPAC2M,CAAC;AAEvP,eAAO,MAAM,iBAAiB,EAAE,SAAS,IAAI,EAK5C,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,SAAS,IAAI,EAuB5C,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC,CAuD5E,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,MAAM,CAEvE;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,CAGnF;AAED,4FAA4F;AAC5F,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAMrF"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export const UNATTENDED_INSTRUCTIONS_PREFIX = 'This connection runs unattended automation, and its operator has already approved spending. Do not quote prices, estimate costs or ask anyone to confirm a paid action unless the request is about cost; create once, then poll the returned job. ';
|
|
2
|
+
export const DESCRIPTION_EDITS = [
|
|
3
|
+
[
|
|
4
|
+
'Check available workflows and estimated generation costs before creating a video.',
|
|
5
|
+
'Check available workflows before creating a video.',
|
|
6
|
+
],
|
|
7
|
+
];
|
|
8
|
+
export const INSTRUCTION_EDITS = [
|
|
9
|
+
[
|
|
10
|
+
'Once ready, estimate and confirm the paid translation before calling dubbing_create when available with the returned asset id as videoAssetId. ',
|
|
11
|
+
'Once ready, call dubbing_create when available with the returned asset id as videoAssetId. ',
|
|
12
|
+
],
|
|
13
|
+
[
|
|
14
|
+
'Before confirming the paid action, use generations_estimate-cost with workflow=translate-and-dub if its schema supports that option. Show the combined Sync estimate and disclose excluded external provider charges. Without that option or the returned breakdown, the estimate covers lip-sync only; do not present it as the full workflow cost. Confirm the target language and configuration. ',
|
|
15
|
+
'',
|
|
16
|
+
],
|
|
17
|
+
['Confirm the source audio, language and quote before translation-previews_create. ', ''],
|
|
18
|
+
[
|
|
19
|
+
'After a translated audio preview is saved, estimate and confirm a separate lipsync_create-from-assets using that audio;',
|
|
20
|
+
'After a translated audio preview is saved, lipsync with that audio in a separate lipsync_create-from-assets or lipsync_create-timeline;',
|
|
21
|
+
],
|
|
22
|
+
['Confirm script, voice and estimated cost. ', ''],
|
|
23
|
+
[
|
|
24
|
+
'then re-quote the saved asset. Preparation is separate from paid generation. ',
|
|
25
|
+
'then use the saved asset. ',
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
'Before quoting script-driven lipsync, call generations_estimate-cost with the actual replacement script when its schema supports script; use measured audioDuration if the replacement audio already exists. Explain the returned durationEstimate and label script-based pricing approximate until synthesis determines the actual length. Never substitute the full source video duration for replacement speech. Disclose speech synthesis separately. If those inputs are unavailable, estimate spoken duration from the script and label it approximate; do not present a source-video quote as the replacement-script price. Re-estimate after script, audio, model or sync-mode changes. ',
|
|
29
|
+
'',
|
|
30
|
+
],
|
|
31
|
+
];
|
|
32
|
+
export const TOOL_DESCRIPTION_EDITS = {
|
|
33
|
+
assets_create: [
|
|
34
|
+
[' Import first, then estimate and confirm translation.', ' Import first, then translate.'],
|
|
35
|
+
],
|
|
36
|
+
lipsync_create: [
|
|
37
|
+
[
|
|
38
|
+
'Before confirming, estimate using the replacement script or measured audio duration, not the source video length. Script-based quotes are approximate and exclude speech synthesis. ',
|
|
39
|
+
'',
|
|
40
|
+
],
|
|
41
|
+
],
|
|
42
|
+
'lipsync_create-timeline': [['Estimate and confirm before creating; this starts', 'This starts']],
|
|
43
|
+
batches_create: [
|
|
44
|
+
[
|
|
45
|
+
'This is a paid action: every item is billed as its own generation. Before creating, estimate a representative item with generations_estimate-cost, tell the user the item count and the estimated total, and wait for their confirmation. ',
|
|
46
|
+
'Every item is billed as its own generation. ',
|
|
47
|
+
],
|
|
48
|
+
],
|
|
49
|
+
dubbing_create: [
|
|
50
|
+
[' before estimating or calling this tool', ' before calling this tool'],
|
|
51
|
+
[
|
|
52
|
+
'This is a paid action: confirm the requested language, configuration and estimated cost with the user before calling. Use generations_estimate-cost with workflow=translate-and-dub when that input is supported, and disclose any excluded external provider charges. Without the combined breakdown, lip-sync pricing is not the full workflow cost. ',
|
|
53
|
+
'',
|
|
54
|
+
],
|
|
55
|
+
],
|
|
56
|
+
'translation-previews_create': [
|
|
57
|
+
[
|
|
58
|
+
'Create one paid translated-audio preview from a saved audio asset. Confirm language and displayed cost first. ',
|
|
59
|
+
'Create one translated-audio preview from a saved audio asset. ',
|
|
60
|
+
],
|
|
61
|
+
[
|
|
62
|
+
'Final video generation is a separate, explicitly approved lip-sync operation',
|
|
63
|
+
'Final video generation is a separate lip-sync operation',
|
|
64
|
+
],
|
|
65
|
+
],
|
|
66
|
+
// Permission to reuse a voice is consent, not spend, so it stays.
|
|
67
|
+
'dialogue-previews_create': [
|
|
68
|
+
[
|
|
69
|
+
'May clone the source speaker voice and incur synthesis charges; confirm the edits and permission to use that voice before creating.',
|
|
70
|
+
'May clone the source speaker voice; confirm permission to use that voice before creating.',
|
|
71
|
+
],
|
|
72
|
+
],
|
|
73
|
+
'dialogue-videos_create': [
|
|
74
|
+
[
|
|
75
|
+
"This is a paid action that starts a generation job and consumes Sync credits. First use dialogue-videos_estimate with the same source, preview and model, then obtain the user's approval of the preview, configuration and estimated cost. ",
|
|
76
|
+
'This starts a generation job. ',
|
|
77
|
+
],
|
|
78
|
+
],
|
|
79
|
+
'speech-previews_create': [[' This is a potentially paid action.', '']],
|
|
80
|
+
'audio-trims_create': [
|
|
81
|
+
['Explain and confirm the partial duration first. ', ''],
|
|
82
|
+
[
|
|
83
|
+
'use its assetId and actual duration for a fresh quote.',
|
|
84
|
+
'use its assetId and actual duration.',
|
|
85
|
+
],
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
export function applyEdits(text, edits) {
|
|
89
|
+
return edits.reduce((result, [from, to]) => result.replace(from, to), text);
|
|
90
|
+
}
|
|
91
|
+
export function withoutSpendConfirmation(tool) {
|
|
92
|
+
const edits = TOOL_DESCRIPTION_EDITS[tool.name];
|
|
93
|
+
return edits ? { ...tool, description: applyEdits(tool.description, edits) } : tool;
|
|
94
|
+
}
|
|
95
|
+
/** SYNC_MCP_SPEND_CONFIRMATION accepts off/false/0 (unattended) and on/true/1 (default). */
|
|
96
|
+
export function parseSpendConfirmation(value) {
|
|
97
|
+
if (value === undefined || value.trim() === '')
|
|
98
|
+
return undefined;
|
|
99
|
+
const normalized = value.trim().toLowerCase();
|
|
100
|
+
if (['off', 'false', '0', 'no'].includes(normalized))
|
|
101
|
+
return false;
|
|
102
|
+
if (['on', 'true', '1', 'yes'].includes(normalized))
|
|
103
|
+
return true;
|
|
104
|
+
throw new Error(`SYNC_MCP_SPEND_CONFIRMATION must be on or off, not "${value}"`);
|
|
105
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Who started the current tool call, forwarded with its API requests. */
|
|
2
|
+
export type ToolAttribution = {
|
|
3
|
+
version: 1;
|
|
4
|
+
invocation_source: 'model' | 'ui' | 'background' | 'unknown';
|
|
5
|
+
journey_id?: string;
|
|
6
|
+
action_id?: string;
|
|
7
|
+
conversation_id?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function getToolAnalytics(): ToolAttribution | undefined;
|
|
10
|
+
export declare function runWithToolAnalytics<T>(attribution: ToolAttribution, run: () => T): T;
|
|
11
|
+
//# sourceMappingURL=tool-analytics-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-analytics-context.d.ts","sourceRoot":"","sources":["../src/tool-analytics-context.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,iBAAiB,EAAE,OAAO,GAAG,IAAI,GAAG,YAAY,GAAG,SAAS,CAAC;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAIF,wBAAgB,gBAAgB,IAAI,eAAe,GAAG,SAAS,CAE9D;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAErF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
const context = new AsyncLocalStorage();
|
|
3
|
+
export function getToolAnalytics() {
|
|
4
|
+
return context.getStore();
|
|
5
|
+
}
|
|
6
|
+
export function runWithToolAnalytics(attribution, run) {
|
|
7
|
+
return context.run(attribution, run);
|
|
8
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Tool } from '@modelcontextprotocol/server';
|
|
2
|
+
/**
|
|
3
|
+
* Tool names follow one `<noun>_<verb>` scheme (CRAFT-7786). This is the permanent record
|
|
4
|
+
* of every rename, old → new: operationIdToToolName names generated tools through it,
|
|
5
|
+
* nameTakenByRenamedTool reserves its new names, and analytics report the old names.
|
|
6
|
+
* Never delete entries; ending the old names' deprecation is OLD_NAME_ALIASES below.
|
|
7
|
+
*/
|
|
8
|
+
export declare const RENAMED_TOOLS: Readonly<Record<string, string>>;
|
|
9
|
+
/** The current name for a name derived from an operationId or used before the rename. */
|
|
10
|
+
export declare function currentToolName(name: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* True when a generated tool's derived name is already a renamed tool's new name, such as
|
|
13
|
+
* StudioViewsController_get → studio-views_get. The hand-written tool owns that name, so
|
|
14
|
+
* the raw operation is never exposed under it.
|
|
15
|
+
*/
|
|
16
|
+
export declare function nameTakenByRenamedTool(derived: string): boolean;
|
|
17
|
+
/** The name a tool had before the rename, if it changed. Permanent; see oldNameAlias. */
|
|
18
|
+
export declare function previousToolName(name: string): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Temporary: the old names that stay callable, as unlisted aliases that add a notice
|
|
21
|
+
* naming the new tool, and that app profiles list as app-only tools because retained
|
|
22
|
+
* Studio bundles and widget templates call them. Remove names here (eventually all of
|
|
23
|
+
* them) to end the deprecation; RENAMED_TOOLS and generated tool names stay as they are.
|
|
24
|
+
*/
|
|
25
|
+
export declare const OLD_NAME_ALIASES: ReadonlySet<string>;
|
|
26
|
+
/** The old name still callable for this tool during the deprecation, if any. */
|
|
27
|
+
export declare function oldNameAlias(name: string, aliases?: ReadonlySet<string>): string | undefined;
|
|
28
|
+
export declare function renamedToolNotice(legacy: string, name: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Widgets cannot call a tool that is not listed, and ChatGPT keeps earlier Studio bundles
|
|
31
|
+
* and widget templates that call tools by their old names. On app profiles, list those
|
|
32
|
+
* old names as app-only tools (the model does not see them) for the deprecation period.
|
|
33
|
+
*/
|
|
34
|
+
export declare function withLegacyAppDescriptors(descriptors: Tool[]): Tool[];
|
|
35
|
+
//# sourceMappingURL=tool-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-names.d.ts","sourceRoot":"","sources":["../src/tool-names.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmE1D,CAAC;AAMF,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAID;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEjE;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAuC,CAAC;AAEzF,gFAAgF;AAChF,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAW,CAAC,MAAM,CAAoB,GAC9C,MAAM,GAAG,SAAS,CAGpB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAoBpE"}
|